using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Collections;
using System.Windows.Forms;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Resources;
using ObjectLib;
using EngMATLib;
using FftLib;
using BmgNet;
using StaticUtility;

namespace ObjectParser
{
    /// <summary>
    /// The type of tool.
    /// </summary>
    public enum ToolType
    {
        None,
        Polygon,
        Contour,
        Circle
    }
    /// <summary>
    /// The polygon tool.  Highlights the active polygon.
    /// Normal Mode:  Highlights the active leg by highlighting both vertices.
    /// Normal Left Down:  Shows a new vertex that splits the old leg into two legs.  Vertex and polygon moves with mouse.
    /// Normal Left Up:  Places the new vertex at the mouse pointer's location.
    /// Ctrl Mode:  Highlights a single active vertex.
    /// Ctrl Left Down:  Picks up the highlighted vertex so that it can be moved.  Vertex and polygon moves with mouse.
    ///	Ctrl Left Up:  Places the vertex at the mouse pointer's location.
    ///	Ctrl+Shift Left Up:  Removes the vertex from the polygon.
    /// </summary>
    public class PathTool
    {
        /// <summary>
        /// The owner of the object.
        /// </summary>
        public FormParse Owner;
        /// <summary>
        /// Denotes if a key or button is down.
        /// </summary>
        public bool CtrlKeyIsDown,ShiftKeyIsDown,MovingPathPt,AddingPathPt,MovingContourPt,AddingContourPt;
        /// <summary>
        /// Denotes if LinkMode is on.  Toggle this by pressing "L" on keyboard.
        /// </summary>
        public bool LinkMode
        {
            get
            {
                return Owner.bLinkMode.ImageIndex==1;
            }
            set
            {
                //	If a toggle is requested
                if((value && Owner.bLinkMode.ImageIndex==0) || (!value && Owner.bLinkMode.ImageIndex==1))
                {
                    Owner.bLinkMode.ImageIndex = 1-Owner.bLinkMode.ImageIndex;
                    //	If LinkMode
                    if(Owner.bLinkMode.ImageIndex==1)
                    {
                        PolygonF act = Owner.Opd.ActivePoly;
                        if(act != null && NewBridge==null)
                        {
                            if(act.Count > 1)
                            {
                                if(Owner.Opd.ActiveCategory.PixExcludeNode != null)
                                {
                                    LinkStage = 1;

                                    LmImgBase1 = new VertexF(-1,-1,null,null);
                                    _LmImgBase1 = new VertexF(-1,-1,null,null);
                                    LmImgTar1 = new VertexF(-1,-1,null,null);
                                    _LmImgTar1 = new VertexF(-1,-1,null,null);
                                    LmImgBase2 = new VertexF(-1,-1,null,null);
                                    _LmImgBase2 = new VertexF(-1,-1,null,null);

                                    LmPbBase1 = new PointF(-1,-1);
                                    _LmPbBase1 = new PointF(-1,-1);
                                    LmPbTar1 = new PointF(-1,-1);
                                    _LmPbTar1 = new PointF(-1,-1);
                                    LmPbBase2 = new PointF(-1,-1);
                                    _LmPbBase2 = new PointF(-1,-1);

                                    Owner.Pb.Invalidate();
                                }
                                else
                                    Owner.bLinkMode.ImageIndex=0; //LinkMode = false;
                            }
                            else
                                Owner.bLinkMode.ImageIndex=0; //LinkMode = false;
                        }
                        else
                            Owner.bLinkMode.ImageIndex=0; //LinkMode = false;
                    }
                    //	Else !LinkMode
                    else
                    {
                        LinkStage = 0;
						UpdateVertexDraw();
                        UpdateInactivePaths();
                        Owner.Pb.Invalidate();
                    }
                    Owner.bLinkMode.Invalidate();
                }
            }
        }
        /// <summary>
        /// Toggle link mode.
        /// </summary>
        /// <returns>Returns true if a toggle was actually executed.</returns>
        public bool ToggleLinkMode()
        {
            bool oldMode = LinkMode;
            LinkMode = !LinkMode;
            return oldMode!=LinkMode;
        }
        /// <summary>
        /// Stage 1:  The "L" button was just selected and we enter LinkMode.  User must select Base 1.
        /// Stage 2:  User must select Target 1.
        ///	Stage 3:  GlidePath to select Target 2.
        ///				From Target 2, there will be only 1 possibility for Base 2.  Auto select it.
        /// </summary>
        public int LinkStage;
        /// <summary>
        /// The insertion index.  Updated internally when UpdateVertexDraw() calls NearestActivePolyLeg()
        /// </summary>
        public int PolyInsertInd;
        /// <summary>
        /// Pb coordinates of a stylus that the user is using (via the mouse) to point something out.
        /// Stylus is for the brush / eraser, PbStylus is for the poly pen.
        /// </summary>
        public Point PbStylus,_PbStylus;
        /// <summary>
        /// Pens.
        /// </summary>
        public Pen PenPt,PenPtDot,PenPtThick,PenLine,PenLineDot,PenRedLine,PenBlueLine,
            PenEdgeIn,PenEdgeOut,PenLineDash,PenXjunc,PenTjunc;
        public OcclusionBridge NewBridge=null;
        /// <summary>
        /// When moving a VertexF, this is the VertexF in question.
        /// </summary>
        public VertexF ImgMovedPathPt,_ImgMovedPathPt,PbMovedPathPt,_PbMovedPathPt;
        /// <summary>
        /// The starting point when the ImgMovedPathPt is moved.  This enables a record of the movement to be recorded in Undo.
        /// </summary>
        public PointF ImgMovedPathPtStart;
        /// <summary>
        /// At OnMouseDown, this is recorded as Owner.Opd.ActiveThing.
        /// </summary>
        public object ActiveAtFirstMouseDown;
        /// <summary>
        /// Denotes whether each element of PbLeg should be drawn.
        /// </summary>
        public bool[] DrawPts,_DrawPts;
        /// <summary>
        /// Denotes the Pb coordinates of each vertex on the leg.
        /// </summary>
        public VertexF[] PbLeg,_PbLeg;
        /// <summary>
        /// Denotes the Img coordinates of each vertex on the leg.
        /// </summary>
        public VertexF[] ImgLeg,_ImgLeg;
        /// <summary>
        /// The radius of a polygon vertex in Pb coordinates.
        /// </summary>
        public const int RADIUS = 5;
        /// <summary>
        /// Initializes the tool.  Only needs to be called once after the project is loaded.
        /// </summary>
        /// <param name="owner">FormParse  The instance of FormParse that controls this tool.</param>
        public PathTool(FormParse owner)
        {
            Owner = owner;
            InitPens();
            PbStylus = new Point(0,0);
            LinkMode = CtrlKeyIsDown = ShiftKeyIsDown = MovingPathPt = AddingPathPt = false;

            DrawPts = new bool[2];
            _DrawPts = new bool[2];
            PbLeg = new VertexF[] { new VertexF(0.0f,0.0f,null,null),new VertexF(0.0f,0.0f,null,null) };
            _PbLeg = new VertexF[] { new VertexF(0.0f,0.0f,null,null),new VertexF(0.0f,0.0f,null,null) };
            ImgLeg = new VertexF[] { new VertexF(0.0f,0.0f,null,null),new VertexF(0.0f,0.0f,null,null) };
            _ImgLeg = new VertexF[] { new VertexF(0.0f,0.0f,null,null),new VertexF(0.0f,0.0f,null,null) };

            ImgMovedPathPt = new VertexF(0.0f,0.0f,null,null);
            _ImgMovedPathPt = new VertexF(0.0f,0.0f,null,null);
            PbMovedPathPt = new VertexF(0.0f,0.0f,null,null);
            _PbMovedPathPt = new VertexF(0.0f,0.0f,null,null);

            ImgMovedPathPtStart = new PointF(0,0);

            InactivePaths = new ArrayList();
            newInactivePaths = new ArrayList();
        }
        /// <summary>
        /// Re-initializes the pens based on the colors stored in Owner.Opd.
        /// </summary>
        public void InitPens()
        {
            PenPt = new Pen(Owner.Opd.PolyLineColor,1.0f);

            PenPtDot = new Pen(Owner.Opd.PolyLineColor,1.0f);
            PenPtDot.DashOffset = 4.0f;
            PenPtDot.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;

            PenPtThick = new Pen(Owner.Opd.PolyLineColor,2.0f);

            PenLine = new Pen(Owner.Opd.PolyLineColor,1.0f);
            PenRedLine = new Pen(Color.Red,2.0f);
            PenBlueLine = new Pen(Color.Blue,2.0f);

            PenLineDot = new Pen(Owner.Opd.PolyLineColor,1.0f);
            PenLineDot.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
            PenLineDot.DashOffset = 4.0f;

            PenLineDash = new Pen(Color.Red,2.0f);
            PenLineDash.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
            PenLineDash.DashPattern = new float[] { 2.0f,2.0f };

            PenEdgeIn = new Pen(Color.Yellow,2.0f);
            PenEdgeIn.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;

            PenEdgeOut = new Pen(Color.Blue,2.0f);
            PenEdgeOut.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;

            PenXjunc = new Pen(Color.FromArgb(200,255,0),1.0f);
            PenTjunc = new Pen(Color.FromArgb(255,200,0),1.0f);
        }
        /// <summary>
        /// Computes information by use in FormParse.  Helps FormParse decide which polygon points to highlight as the polygon
        /// tool glides around the picture-box control FormParse.Pb.
        /// </summary>
        /// <param name="refPt">PointF  An Img point in reference to the active polygon.</param>
        /// <param name="drawPt">out  bool[2]  If the polygon has more than 2 points, both elements are true.  If 1 or 2 points,
        /// then only the first element is true.  If zero points, then no elements are true.</param>
        /// <param name="pt">out  VertexF[2]  For each true element of drawPt, a meaningful Img vertex is returned.  If the polygon
        /// has more than 2 points, then the first point returned is the closest point to refPt.  Then the second point
        /// is the point attached to the leg of the polygon closest to refPt.  If the polygon has 1 or 2 points, then
        /// the closest point on the polygon is the first element of this vector.  If the polygon has 0 points, then
        /// this is empty.</param>
        /// <param name="insertAt">int  Gives the index to insert a new point into the polygon if the polygon tool
        /// becomes activated at this moment.</param>
        public void NearestActivePathLeg(PointF refPt,out bool[] drawPt,out VertexF[] pt,out int insertAt)
        {
            double legBack,legFront,legPt,cosBack,sinBack,cosFront,sinFront;
            pt = new VertexF[2];
            drawPt = new bool[2];
            insertAt = 0;
            PolygonF actPoly = Owner.Opd.ActivePoly;
            ContourF actCon = Owner.Opd.ActiveContour;
            if(Owner.CurrentTool!=ToolType.Contour)
                actCon=null;
            #region PolygonF check
            if(actPoly != null && actCon == null)
            {
                if(actPoly.Count==1)		//	One point in active polygon.  Draw it.
                {
                    drawPt[0] = true;
                    pt[0] = actPoly[0];
                }
                else if(actPoly.Count==2)		//	Two points in active polygon.  Draw the single closest point.
                {
                    drawPt[0]=true;
                    if(VertexF.Distance(actPoly[0],refPt) < VertexF.Distance(actPoly[1],refPt))
                    {
                        pt[0] = actPoly[0];
                        pt[1] = actPoly[1];
                    }
                    else
                    {
                        pt[0] = actPoly[1];
                        pt[1] = actPoly[0];
                    }
                }
                else if(actPoly.Count>2)//	More than two points.  Draw the closest point and its mate, which is the point attached to the closest segment.
                {
                    drawPt[0]=drawPt[1]=true;
                    float dMin,d;
                    int iMin=0;
                    dMin = VertexF.Distance(actPoly[0],refPt);
                    for(int j=1;j<actPoly.Count;j++)	//	Get the closest point iMin.
                    {
                        d = VertexF.Distance(actPoly[j],refPt);
                        if(d<dMin)
                        {
                            dMin = d;
                            iMin = j;
                        }
                    }
                    pt[0] = (actPoly[iMin]);
                    int iBack,iFront,insertBack,insertFront;
                    if(iMin==0)
                    {
                        iBack = actPoly.Count-1;
                        iFront = iMin+1;
                        insertBack = actPoly.Count;
                        insertFront = iFront;
                    }
                    else if(iMin==actPoly.Count-1)
                    {
                        iBack = iMin-1;
                        iFront = 0;
                        insertBack = iMin;
                        insertFront = 0;
                    }
                    else
                    {
                        iBack = iMin-1;
                        iFront = iMin+1;
                        insertBack = iMin;
                        insertFront = iFront;
                    }

                    legBack = Math.Atan2(actPoly[iBack].Y-actPoly[iMin].Y,actPoly[iBack].X-actPoly[iMin].X);
                    legFront = Math.Atan2(actPoly[iFront].Y-actPoly[iMin].Y,actPoly[iFront].X-actPoly[iMin].X);
                    legPt = Math.Atan2(actPoly[iMin].Y-refPt.Y,actPoly[iMin].X-refPt.X);
                    cosBack = Math.Cos(legBack)-Math.Cos(legPt);
                    sinBack = Math.Sin(legBack)-Math.Sin(legPt);
                    cosFront = Math.Cos(legFront)-Math.Cos(legPt);
                    sinFront = Math.Sin(legFront)-Math.Sin(legPt);

                    //	Backward leg is mated
                    if(cosBack*cosBack + sinBack*sinBack > cosFront*cosFront + sinFront*sinFront)
                    {
                        insertAt = insertBack;
                        pt[1] = actPoly[iBack];
                    }
                    else	//	forward leg is mated
                    {
                        insertAt = insertFront;
                        pt[1] = actPoly[iFront];
                    }
                }
            }
            #endregion
            #region ContourF check
            else if(actCon != null)
            {
                if(actCon.Count==1)		//	One point in active polygon.  Draw it.
                {
                    drawPt[0] = true;
                    pt[0] = actCon[0];
                }
                else if(actCon.Count>1)//	More than one point.  Draw the closest point and its mate (if not an end point), which is the point attached to the closest segment.
                {
                    drawPt[0]=drawPt[1]=true;
                    float dMin,d;
                    int iMin=0;
                    dMin = VertexF.Distance(actCon[0],refPt);
                    for(int j=1;j<actCon.Count;j++)	//	Get the closest point iMin.
                    {
                        d = VertexF.Distance(actCon[j],refPt);
                        if(d<dMin)
                        {
                            dMin = d;
                            iMin = j;
                        }
                    }
                    pt[0] = (actCon[iMin]);
                    int iBack,iFront;
                    if(iMin==0)
                    {
                        iBack = -1;
                        iFront = iMin+1;
                        legFront = Math.Atan2(actCon[iFront].Y-actCon[iMin].Y,actCon[iFront].X-actCon[iMin].X);
                        legBack = legFront+Math.PI;
                    }
                    else if(iMin==actCon.Count-1)
                    {
                        iBack = iMin-1;
                        iFront = iMin+1;
                        legBack = Math.Atan2(actCon[iBack].Y-actCon[iMin].Y,actCon[iBack].X-actCon[iMin].X);
                        legFront = legBack+Math.PI;
                    }
                    else
                    {
                        iBack = iMin-1;
                        iFront = iMin+1;
                        legBack = Math.Atan2(actCon[iBack].Y-actCon[iMin].Y,actCon[iBack].X-actCon[iMin].X);
                        legFront = Math.Atan2(actCon[iFront].Y-actCon[iMin].Y,actCon[iFront].X-actCon[iMin].X);
                    }

                    legPt = Math.Atan2(actCon[iMin].Y-refPt.Y,actCon[iMin].X-refPt.X);
                    cosBack = Math.Cos(legBack)-Math.Cos(legPt);
                    sinBack = Math.Sin(legBack)-Math.Sin(legPt);
                    cosFront = Math.Cos(legFront)-Math.Cos(legPt);
                    sinFront = Math.Sin(legFront)-Math.Sin(legPt);

                    //	Backward angle is selected
                    if(cosBack*cosBack + sinBack*sinBack > cosFront*cosFront + sinFront*sinFront)
                    {
                        insertAt = iMin;
                        if(iBack<0)
                        {
                            drawPt[1]=false;
                            pt[1]=actCon[iFront];
                        }
                        else
                            pt[1]=actCon[iBack];
                    }
                    //	Forward angle is selected
                    else
                    {
                        insertAt = iFront;
                        if(iFront >= actCon.Count)
                        {
                            drawPt[1]=false;
                            pt[1]=actCon[iBack];
                        }
                        else
                            pt[1]=actCon[iFront];
                    }
                }
            }
            #endregion
        }
        /// <summary>
        /// Updates the values of the vertices.  Invalidates parts of the image where required when selected vertices change.
        /// Updates internal variables to make the next call possible.
        /// </summary>
        public void UpdateVertexDraw()
        {
            //	PATH FUNCTIONALITY, nearest leg.
            PolygonF actPoly = Owner.Opd.ActivePoly;
            PathF actPath = actPoly;
            ContourF actCon = Owner.Opd.ActiveContour;
            if(Owner.CurrentTool!=ToolType.Contour)
                actCon=null;
            else
                actPath = actCon;
            PointF refPt = new PointF(Owner.PbToImgX((float)PbStylus.X),Owner.PbToImgY((float)PbStylus.Y));
            if(!MovingPathPt)
            {
                //	Update the representation of the nearest legs for the active polygon.
                NearestActivePathLeg(refPt,out DrawPts,out ImgLeg,out PolyInsertInd);

                //	Check for new InactivePaths.  Maintain and invalidate them as necessary.
                if(DrawPts[0])
                {
                    PointF[] points;
                    PointF[] pup = new PointF[4];	//	The changed region.
                    PathF path;
                    for(int i=0;i<ImgLeg[0].Polygons.Count;i++)		//	For each owner of the vertex ImgLeg[0]
                    {
                        path = ImgLeg[0].Polygons[i];
                        if(path != actPath) //	that isn't the active path
                        {
                            if(InactivePaths.Contains(path))		//	Polygon is not yet registered as inactive.
                            {
                                InactivePaths.Add(path);			//	So add it.
                                Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(path.PbPath,RADIUS+2)));
                            }
                            else									//	Polygon is registered as inactive
                            {
                                //	change the location of the point and invalidate.
                                int j = path.IndexOf(ImgLeg[0]);	//	index of vertex
                                points = path.PbPath;				//	points for polygon.

                                if(points!=null)
                                {
                                    pup[0] = points[j];
                                    int prev = j-1;
                                    if(prev < 0)
                                        prev = points.Length-1;

                                    int next = j+1;
                                    if(next > points.Length-1)
                                        next = 0;

                                    pup[1] = points[prev];
                                    pup[2] = points[j] = new PointF(Owner.ImgToPbX(ImgLeg[0].X),Owner.ImgToPbY(ImgLeg[0].Y));
                                    pup[3] = points[next];

                                    Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(pup,RADIUS+1)));
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                //	Before updating the moving polygon coordinates,  invalidate the old polygons.
                int ind = actPath.IndexOf(ImgMovedPathPt);
                if(ind >= 0)
                {
                    //	Invalidate the legs of inactive polygons that own this moving point.
                    //	Update any InactivePaths
                    PathF path;
                    for(int i=0;i<ImgMovedPathPt.Polygons.Count;i++)
                    {
                        path = ImgMovedPathPt.Polygons[i];
                        Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(path.PbPath,RADIUS+2)));
                    }
                }

                //	Record the last known values of the MovedPathPt.
                _ImgMovedPathPt.MimicValuesOf(ImgMovedPathPt);
                _PbMovedPathPt.MimicValuesOf(PbMovedPathPt);

                //	Update the new values of the MovedPathPt.
                ImgMovedPathPt.X = refPt.X;
                ImgMovedPathPt.Y = refPt.Y;
                PbMovedPathPt.X = PbStylus.X;
                PbMovedPathPt.Y = PbStylus.Y;

                if(ind >= 0)
                {
                    actPath.PbPath[ind] = PbMovedPathPt.PointF;

                    //	Invalidate the legs of inactive polygons that own this moving point.
                    //	Update any InactivePaths
                    PathF path;
                    for(int i=0;i<ImgMovedPathPt.Polygons.Count;i++)
                    {
                        path = ImgMovedPathPt.Polygons[i];
                        if(InactivePaths.Contains(path))
                        {
                            InactivePaths.Add(path);
                            Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(path.PbPath,RADIUS+2)));
                        }
                        else
                        {
                            int j = path.IndexOf(ImgMovedPathPt);
							path.PbPath[j] = PbMovedPathPt.PointF;
                        }
                    }
                    for(int i=0;i<ImgMovedPathPt.Contours.Count;i++)
                    {
                        path = ImgMovedPathPt.Contours[i];
                        if(InactivePaths.Contains(path))
                        {
                            InactivePaths.Add(path);
                            Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(path.PbPath,RADIUS+2)));
                        }
                        else
                        {
                            int j = path.IndexOf(ImgMovedPathPt);
                            path.PbPath[j] = PbMovedPathPt.PointF;
                        }
                    }

                    //	Invalidate the new and old points to facilitate movement across screen.
                    Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetPtDrawRect(PbMovedPathPt,RADIUS+1)));
                    Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetPtDrawRect(_PbMovedPathPt,RADIUS+1)));
                }
            }

            //	Rectangle that bounds the last location of the moved point and the current location of the moved point.
            Rectangle rBound = VertexF.GetBoundingRect(PbMovedPathPt,_PbMovedPathPt,RADIUS+1);

            //	Update all picture-box coordinates
            for(int i=0;i<2;i++)		//	For each of two points.
            {
                if(DrawPts[i])
                {
                    //	Update this poly leg into Pb coordinates.
                    PbLeg[i].X = Owner.ImgToPbX(ImgLeg[i].X);
                    PbLeg[i].Y = Owner.ImgToPbY(ImgLeg[i].Y);

                    //	Invalidate new point.
                    Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(PbLeg[i],(float)(RADIUS+1))));

                    //	If the leg needs to be drawn for a Moving point.
                    if(MovingPathPt && Owner.Opd.ActivePoly.Count>2)
                    {
                        //	Update the nearest poly leg points into Pb coordinates.
                        PbLeg[i].X = Owner.ImgToPbX(ImgLeg[i].X);
                        PbLeg[i].Y = Owner.ImgToPbY(ImgLeg[i].Y);
                        // rectangle that bounds rBound and PbLeg[i]
                        Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(rBound,PbLeg[i],(float)(RADIUS+1))));
                    }
                }
                //	The old point was drawn before but not the new point.
                if(_DrawPts[i])
                {
                    //	Invalidate the old point.
                    if(_PbLeg[i]!=PbLeg[i])
                        Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(_PbLeg[i],(float)(RADIUS+1))));
                    //	If the leg needs to be drawn for a Moving point.
                    if(MovingPathPt && Owner.Opd.ActivePoly.Count>2)
                        // rectangle that bounds rBound and _PbLeg[i]
                        Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(rBound,_PbLeg[i],(float)(RADIUS+1))));
                }
                //	Update the old point to be equal to the new point.
                _DrawPts[i] = DrawPts[i];
                _PbLeg[i].MimicValuesOf(PbLeg[i]);
                _ImgLeg[i].MimicValuesOf(ImgLeg[i]);
            }
        }
        /// <summary>
        /// Invalidates a leg given the rectangles that surround the vertex for each leg.  This is all in Pb coordinates.
        /// </summary>
        /// <param name="r1"></param>
        /// <param name="r2"></param>
        public void InvalidateLeg(Rectangle r1,Rectangle r2)
        {
            int l,t,r,b;
            l = Math.Min(r1.Left,r2.Left);
            t = Math.Min(r1.Top,r2.Top);
            r = Math.Max(r1.Right,r2.Right);
            b = Math.Max(r1.Bottom,r2.Bottom);
            Owner.Pb.Invalidate(Owner.InvPbRect(new Rectangle(l,t,r-l+1,b-t+1)));
        }
        /// <summary>
        /// The PolygonF objects that are to be drawn as inactive.
        /// </summary>
        public ArrayList InactivePaths;
        /// <summary>
        /// When a polygon is cut, this is it.
        /// </summary>
        public PolygonF CutPoly;
        /// <summary>
        /// Used internally to update InactivePaths in the UpdateInactivePaths function.
        /// </summary>
        private ArrayList newInactivePaths;
        public PolygonFarray LastPaintedSwallowed = null;
        public PolygonF LastPaintedSwallowedBy = null;
        /// <summary>
        /// Updates the list of InactivePaths.
        /// </summary>
        public void UpdateInactivePaths()
        {
            PolygonF actPoly = Owner.Opd.ActivePoly;
            ContourF actCon = Owner.Opd.ActiveContour;
            PathF actPath = actPoly;
            if(actCon!=null)
                actPath = actCon;
            if(actPoly != null)
            {
                int i;
                //	Worry about the inactive polygons
                //	Record the PolygonF objects that need to be part of InactivePaths.
                if(DrawPts[1])		//	There are two neighboring vertices.  Check for InactivePaths.
                {
                    for(i=0;i<ImgLeg[0].Polygons.Count;i++)		//	Append its Polygons onto the new PolyPt.
                        if(ImgLeg[0].Polygons[i]!=actPoly && ImgLeg[1].Polygons.Contains(ImgLeg[0].Polygons[i]))
                            newInactivePaths.Add(ImgLeg[0].Polygons[i]);
                    for(i=0;i<ImgLeg[0].Contours.Count;i++)		//	Append its Contours onto the new PolyPt.
                        if(ImgLeg[0].Contours[i]!=actCon && ImgLeg[1].Contours.Contains(ImgLeg[0].Contours[i]))
                            newInactivePaths.Add(ImgLeg[0].Contours[i]);
                }

                //	Invalidate based on differences of the new and old lists.
                int ind;
                PathF pf;
                for(i=0;i<newInactivePaths.Count;i++)
                {
                    pf = (PathF)newInactivePaths[i];
                    ind = InactivePaths.IndexOf(pf);
                    if(ind < 0)		//	A new path is being added.  invalidate it.
                        Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(pf.PbPath,RADIUS+1)));
                    else			//	The path exists already.  Just remove it from the old list.
                        InactivePaths.RemoveAt(ind);
                }
                /*
                while(InactivePaths.Count>0)		//	Invalidate any old paths that don't need to be repainted.
                {
                    pf = (PathF)InactivePaths[0];
                    Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(pf.PbPath,RADIUS+1)));
                    InactivePaths.RemoveAt(0);
                }
                */
				for(i=InactivePaths.Count-1;i>=0;i--)
				{
					pf = (PathF)InactivePaths[i];
					Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(pf.PbPath,RADIUS+1)));
					InactivePaths.RemoveAt(i);
				}

                ArrayList temp = InactivePaths;
                InactivePaths = newInactivePaths;
                newInactivePaths = temp;
            }
        }
        public void UpdateSwallowed()
        {
            PolygonF active = Owner.Opd.ActivePoly;
            if(active.Swallowed != null)
                for(int i=0;i<active.Swallowed.Count;i++)
                    Owner.Pb.Invalidate(Owner.InvPbRect(active.Swallowed[i].GetBoundingRect(1)));
            if(active.SwallowedBy != null)
                Owner.Pb.Invalidate(Owner.InvPbRect(active.SwallowedBy.GetBoundingRect(1)));
            //	Invalidate LastPaintedSwallowed and LastPaintedSwallowedBy.
            if(LastPaintedSwallowed != null)
                for(int i=0;i<LastPaintedSwallowed.Count;i++)
                    Owner.Pb.Invalidate(Owner.InvPbRect(LastPaintedSwallowed[i].GetBoundingRect(1)));
            if(LastPaintedSwallowedBy != null)
                Owner.Pb.Invalidate(Owner.InvPbRect(LastPaintedSwallowedBy.GetBoundingRect(1)));
        }
        public VertexF LmImgBase1,_LmImgBase1,LmImgTar1,_LmImgTar1,LmImgBase2,_LmImgBase2,LmBase2_1,LmBase2_2;
        public PointF LmPbBase1,_LmPbBase1,LmPbTar1,_LmPbTar1,LmPbBase2,_LmPbBase2;
        public GlidePath Glider;
        public void UpdateLinkDraw()
        {
            //	The active polygon.
            for(int i=0;i<2;i++)
            {
                if(DrawPts[i])
                {
                    PbLeg[i].X = Owner.ImgToPbX(ImgLeg[i].X);
                    PbLeg[i].Y = Owner.ImgToPbY(ImgLeg[i].Y);
                    _PbLeg[i].X = Owner.ImgToPbX(_ImgLeg[i].X);
                    _PbLeg[i].Y = Owner.ImgToPbY(_ImgLeg[i].Y);
                }
            }
            UpdateInactivePaths();

            LmPbBase1.X = Owner.ImgToPbX(LmImgBase1.X);
            LmPbBase1.Y = Owner.ImgToPbY(LmImgBase1.Y);
            _LmPbBase1.X = Owner.ImgToPbX(_LmImgBase1.X);
            _LmPbBase1.Y = Owner.ImgToPbY(_LmImgBase1.Y);

            if(LinkStage == 4)
            {
                LmPbBase2.X = Owner.ImgToPbX(LmImgBase2.X);
                LmPbBase2.Y = Owner.ImgToPbY(LmImgBase2.Y);
                _LmPbBase2.X = Owner.ImgToPbX(_LmImgBase2.X);
                _LmPbBase2.Y = Owner.ImgToPbY(_LmImgBase2.Y);
            }
            if(LinkStage == 3)
            {
                Glider.UpdateDrawCache();

                LmPbTar1.X = Owner.ImgToPbX(LmImgTar1.X);
                LmPbTar1.Y = Owner.ImgToPbY(LmImgTar1.Y);
                _LmPbTar1.X = Owner.ImgToPbX(_LmImgTar1.X);
                _LmPbTar1.Y = Owner.ImgToPbY(_LmImgTar1.Y);
            }
            if(LinkStage == 2)
            {
                LmPbTar1.X = Owner.ImgToPbX(LmImgTar1.X);
                LmPbTar1.Y = Owner.ImgToPbY(LmImgTar1.Y);
                _LmPbTar1.X = Owner.ImgToPbX(_LmImgTar1.X);
                _LmPbTar1.Y = Owner.ImgToPbY(_LmImgTar1.Y);
            }
        }
        public static int NextInd(int length,int currentInd)
        {
            int output = currentInd+1;
            if(output > length-1) output = 0;
            return output;
        }
        public static int LastInd(int length,int currentInd)
        {
            int output = currentInd-1;
            if(output < 0) output = length-1;
            return output;
        }
        public static int NextIndInDirection(int length,int i1,int i2)
        {
            if(i2==LastInd(length,i1))	//	going backwards
                return LastInd(length,i1);
            return NextInd(length,i2);
        }
        public static int LastIndInDirection(int length,int i1,int i2)
        {
            return NextIndInDirection(length,i2,i1);
        }
        public static int InsertBetweenPolyInd(int length,int i1,int i2)
        {
            if(i2==LastInd(length,i1))
                return i1;
            else return i2;
        }
        public Bitmap GetBitmap(object o)
        {
            if(o.GetType() == typeof(PolygonF))
            {
                PolygonF pf = (PolygonF)o;
                if(pf == Owner.Opd.ActivePoly)
                    return null;
                if(pf.Owner==Owner.Opd.ActiveObject)
                    return Owner.BmpCurrentObj;
                if(pf.Owner.Category==Owner.Opd.ActiveCategory)
                    return Owner.BmpOtherObj;
                if(pf.Owner.Category.PixExcludeNode==Owner.Opd.ActiveCategory.PixExcludeNode)
                    return Owner.BmpNonObj;
            }
            else if(o.GetType() == typeof(ParsedObject))
            {
                ParsedObject od = (ParsedObject)o;
                if(od==Owner.Opd.ActiveObject)
                    return Owner.BmpCurrentObj;
                if(od.Category==Owner.Opd.ActiveCategory)
                    return Owner.BmpOtherObj;
                if(od.Category.PixExcludeNode==Owner.Opd.ActiveCategory.PixExcludeNode)
                    return Owner.BmpNonObj;
            }
            return null;
        }
        public Color GetColor(object o)
        {
            if(o.GetType() == typeof(PolygonF))
            {
                PolygonF pf = (PolygonF)o;
                if(pf.Owner==Owner.Opd.ActiveObject)
                    return Owner.Opd.ObjCurrColor;
                if(pf.Owner.Category==Owner.Opd.ActiveCategory)
                    return Owner.Opd.ObjOtherColor;
                if(pf.Owner.Category.PixExcludeNode==Owner.Opd.ActiveCategory.PixExcludeNode)
                    return Owner.Opd.ObjNonColor;
            }
            else if(o.GetType() == typeof(ParsedObject))
            {
                ParsedObject od = (ParsedObject)o;
                if(od==Owner.Opd.ActiveObject)
                    return Owner.Opd.ObjCurrColor;
                if(od.Category==Owner.Opd.ActiveCategory)
                    return Owner.Opd.ObjOtherColor;
                if(od.Category.PixExcludeNode==Owner.Opd.ActiveCategory.PixExcludeNode)
                    return Owner.Opd.ObjNonColor;
            }
            return Color.Transparent;
        }
        /// <summary>
        /// Updated for ContourF
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void OnMouseMove(object sender,System.Windows.Forms.MouseEventArgs e)
        {
            _PbStylus = PbStylus;
            PbStylus.X = e.X;
            PbStylus.Y = e.Y;

            ContourF actCon = null;
            if(Owner.CurrentTool==ToolType.Contour)
                actCon = Owner.Opd.ActiveContour;
            PolygonF actPoly = this.Owner.Opd.ActivePoly;

            if(NewBridge!=null)
            {
                Cursor.Current = Cursors.Cross;
                ParsedObject po = actPoly.Owner;
                VertexF vf;
                PolygonF pf;
                //	Find the VertexF on a neighboring polygon (of the same ParsedObject)
                //	that is closest to the mouse pointer.
                po.ClosestVertexF(Owner.PbToImg(Owner.Pb.PointToClient(Cursor.Position)),null,out pf,out vf);
                if(vf!=NewBridge.Vf2)
                {
                    Owner.Pb.Invalidate(VertexF.GetBoundingRect(
                        Owner.ImgToPb(NewBridge.Vf1),
                        Owner.ImgToPb(NewBridge.Vf2),2.0f));
                    NewBridge.Vf2 = vf;
                    NewBridge.Pf2 = pf;
                    Owner.Pb.Invalidate(VertexF.GetBoundingRect(
                        Owner.ImgToPb(NewBridge.Vf1),
                        Owner.ImgToPb(NewBridge.Vf2),2.0f));
                }
            }
            else if(LinkMode)
            {
                if(e.Button == MouseButtons.Right)
                {
                    Cursor.Current = Cursors.Hand;
                    UpdateLinkDraw();
                    if(LinkStage > 2)
                        Glider.UpdateDrawCache();
                }
                else if(e.Button != MouseButtons.Left)
                {
                    Cursor.Current = Cursors.Cross;

                    //	Stage 1:  The "L" button was just selected and we enter LinkMode.  User must select Base 1.
                    //	Stage 2:  User must select Target 1.
                    //	Stage 3:  GlidePath to select Target 2.
                    //	Stage 4:  User must select Base 2 (there will only be two possibilities)
                    PointF refPt = new PointF(Owner.PbToImgX((float)PbStylus.X),Owner.PbToImgY((float)PbStylus.Y));

                    if(LinkStage==1)
                    {
                        //	Echo the old values of Base1.
                        _LmImgBase1.MimicValuesOf(LmImgBase1);
                        _LmPbBase1 = LmPbBase1;

                        //	Update the location of the potential Base 1.
                        NearestActivePathLeg(refPt,out DrawPts,out ImgLeg,out PolyInsertInd);
                        LmImgBase1 = ImgLeg[0];
                        LmPbBase1.X = Owner.ImgToPbX(LmImgBase1.X);
                        LmPbBase1.Y = Owner.ImgToPbY(LmImgBase1.Y);

                        if(LmPbBase1.X != _LmPbBase1.X || LmPbBase1.Y != _LmPbBase1.Y)
                        {
                            //	Using LmPbBase, OnPaint() can highlight the potential Base 1.
                            Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(LmPbBase1,RADIUS+2)));
                            //	Using _LmPbBase, OnPaint() can erase the old Base 1 if it was old.
                            Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(_LmPbBase1,RADIUS+2)));
                        }
                    }
                    else if(LinkStage==2)
                    {
                        //	Highlight the potential Target 1.  Draw a dotted leg from Base1.
                        _LmImgTar1.MimicValuesOf(LmImgTar1);
                        _LmPbTar1 = LmPbTar1;

                        if(actCon==null)
                            LmImgTar1 = Owner.Opd.ActiveCategory.PixExcludeNode.ClosestInactiveVertexF(refPt,actPoly,true);
                        else
                            LmImgTar1 = Owner.Opd.ActiveCategory.PixExcludeNode.ClosestInactiveVertexF(refPt,actCon,true);
                        LmPbTar1.X = Owner.ImgToPbX(LmImgTar1.X);
                        LmPbTar1.Y = Owner.ImgToPbY(LmImgTar1.Y);

                        //	A change has occurred.  Invalidate.
                        if(LmPbBase1.X != _LmPbBase1.X || LmPbBase1.Y != _LmPbBase1.Y || LmPbTar1.X != _LmPbTar1.X || LmPbTar1.Y != _LmPbTar1.Y)
                        {
                            Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(LmPbBase1,LmPbTar1,RADIUS+2)));
                            Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(_LmPbBase1,_LmPbTar1,RADIUS+2)));
                        }

                        //	Draw the new inactive path that we're linking to
                        PathF pf;
                        for(int i=0;i<LmImgTar1.Polygons.Count;i++)
                        {
                            pf = (PathF)LmImgTar1.Polygons[i];
                            if(!InactivePaths.Contains(pf))
                            {
                                InactivePaths.Add(pf);
                                Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(pf.PbPath,RADIUS+1)));
                            }
                        }
                        for(int i=0;i<LmImgTar1.Contours.Count;i++)
                        {
                            pf = (PathF)LmImgTar1.Contours[i];
                            if(!InactivePaths.Contains(pf))
                            {
                                InactivePaths.Add(pf);
                                Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(pf.PbPath,RADIUS+1)));
                            }
                        }

                        //	Wipe out the InactivePaths that we don't need.
                        for(int i=0;i<InactivePaths.Count;i++)
                        {
                            pf = (PathF)InactivePaths[i];
                            if((pf.GetType()==typeof(PolygonF) && !LmImgTar1.Polygons.Contains(pf))
                                    ||  (pf.GetType()==typeof(ContourF) && !LmImgTar1.Contours.Contains(pf)))
                            {
                                Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(pf.PbPath,RADIUS+1)));
                                InactivePaths.RemoveAt(i--);
                            }
                        }
                    }
                    else if(LinkStage==3)
                    {
                        //	Glide path to Target 2 until OnMouseDown.
                        Glider.Update(refPt.X,refPt.Y);
                    }
                    else if(LinkStage==4)
                    {
                        //	Update the location of the potential Base 2.  There are only two options.
                        double dist1 = VertexF.Distance(refPt,LmBase2_1);
                        LmImgBase2 = LmBase2_1;
                        if(LmBase2_2!=null)
                        {
                            double dist2 = VertexF.Distance(refPt,LmBase2_2);
                            if(dist1 >= dist2)
                                LmImgBase2 = LmBase2_2;
                        }

                        LmPbBase2.X = Owner.ImgToPbX(LmImgBase2.X);
                        LmPbBase2.Y = Owner.ImgToPbY(LmImgBase2.Y);

                        PointF pt = new PointF(
                            Owner.ImgToPbX(Glider[Glider.Count-1].Intersection.X),
                            Owner.ImgToPbY(Glider[Glider.Count-1].Intersection.Y));

                        if(LmPbBase2.X != _LmPbBase2.X || LmPbBase2.Y != _LmPbBase2.Y)
                        {
                            //	Using LmPbBase, OnPaint() can highlight the potential Base 1.
                            Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(pt,LmPbBase2,RADIUS+2)));
                            //	Using _LmPbBase, OnPaint() can erase the old Base 1 if it was old.
                            Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(pt,_LmPbBase2,RADIUS+2)));
                        }
                        //	Echo the old values of Base1.
                        _LmImgBase2.MimicValuesOf(LmImgBase2);
                        _LmPbBase2 = LmPbBase2;
                    }
                }
            }
            else	//	Not Link-Mode
            {
                if(e.Button==MouseButtons.Right)	//	Pan the image
                {
                    Cursor.Current = Cursors.Hand;
                    for(int i=0;i<2;i++)
                    {
                        if(DrawPts[i])
                        {
                            PbLeg[i].X = Owner.ImgToPbX(ImgLeg[i].X);
                            PbLeg[i].Y = Owner.ImgToPbY(ImgLeg[i].Y);
                            _PbLeg[i].X = Owner.ImgToPbX(_ImgLeg[i].X);
                            _PbLeg[i].Y = Owner.ImgToPbY(_ImgLeg[i].Y);
                        }
                    }

                }
                else
                {
                    Cursor.Current = Cursors.Cross;
                }
                UpdateVertexDraw();
				UpdateInactivePaths();
            }
        }
        /// <summary>
        /// Cleared for ContourF usage.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void OnMouseDown(object sender,System.Windows.Forms.MouseEventArgs e)
        {
            _PbStylus = PbStylus;
            PbStylus.X = e.X;
            PbStylus.Y = e.Y;
            PolygonF actPoly = Owner.Opd.ActivePoly;
            ContourF actCon = null;
            if(Owner.CurrentTool==ToolType.Contour)
                actCon = Owner.Opd.ActiveContour;

            if(e.Button==MouseButtons.Right)
                Owner.Cursor = Cursors.Hand;

            #region LinkMode (OnMouseDown)
            if(LinkMode && NewBridge==null)
            {
                if(e.Button == MouseButtons.Left)
                {
                    //	Stage 1:  The "L" button was just selected and we enter LinkMode.  User must select Base 1.
                    //	Stage 2:  User must select Target 1.
                    //	Stage 3:  GlidePath to select Target 2.
                    //	Stage 4:  User must select Base 2 (there will only be two possibilities)
                    if(LinkStage==1)
                    {
                        //	Select Base 1 and move to stage 2.
                        if(LmImgBase1.X != -1.0f)
                            LinkStage = 2;
                    }
                    else if(LinkStage==2)
                    {
                        //	Select the potential Target 1, initiate a GlidePath, and move to stage 3.
                        Glider = new GlidePath(new Junction(LmImgTar1,LmImgBase1),this);
                        LinkStage = 3;
                    }
                    else if(LinkStage==3)
                    {
                        if(Glider.Count > 0)
                        {
                            LinkStage = 4;
                            //	The active contour is null, we are on an active polygon.
                            if(actCon==null)
                            {
                                //	Only two choices for base 2.
                                int i = actPoly.IndexOf(Glider[0].Tail);
                                int iBack = i-1;
                                if(iBack<0)
                                    iBack=actPoly.Count-1;
                                int iFront = i+1;
                                if(iFront>actPoly.Count-1)
                                    iFront=0;
                                LmBase2_1 = actPoly[iBack];
                                LmBase2_2 = actPoly[iFront];
                            }
                            else
                            {
                                //	Only two choices for base 2.
                                int i = actCon.IndexOf(Glider[0].Tail);

                                if(Glider.Count==1)
                                {
                                    LmBase2_1 = actCon[i];
                                    LmBase2_2 = null;
                                }
                                else
                                {
                                    int iBack = i-1;
                                    if(iBack>=0)
                                        LmBase2_1 = actCon[iBack];
                                    else
                                        LmBase2_1 = null;
                                    int iFront = i+1;
                                    if(iFront<actCon.Count)
                                        LmBase2_2 = actCon[iFront];
                                    else
                                        LmBase2_2 = null;
                                }
                            }
                        }
                    }
                    else if(LinkStage==4)
                    {
                        ToggleLinkMode();
                        //	Encode the macro that defines this type of link.
                        if(LmImgBase2 != null)
                        {
                            //	Select Target 2, auto-select base 2
                            if(actCon==null)
                                Glider.Attach(actPoly,LmImgBase2,GetBitmap(actPoly),GetColor(actPoly));
                            else
                                Glider.Attach(actCon,LmImgBase2);

                            //	108	Join an edge onto two vertices of the active polygon.
                            //	(	GlidePath glider, PathF pf,
                            //		PolygonFlist toSwallow, PolygonFlist toUnswallow,
                            //		EdgePairArray bustedEdges )
                            //ArrayList macro = new ArrayList();
                            //macro.Add(108);
                            //macro.Add(Glider);
                            //if(actCon==null)
                            //    macro.Add(actPoly);
                            //else
                            //    macro.Add(actCon);

                            //	Check to see if everything is stable.  If not, Undo the action.
                            Rectangle clipRect = Glider.GetBoundingRect();
                            PathFarray paths = Glider.Paths;

                            bool stable = true;

                            //	Check for a polygon leg-crossing violation
                            for(int i=0;i<paths.Count;i++)
                                if(paths[i].GetType()==typeof(PolygonF) && ((PolygonF)paths[i]).IntersectsSelf())
                                    stable = false;

                            PolygonFlist toSwallow = new PolygonFlist();
                            PolygonFlist toUnswallow = new PolygonFlist();

                            //	Check for a swallowing violation
                            if(actCon==null && stable)
                            {
                                PolygonFlist unstable = Owner.Opd.RegionIsStable(Glider.GetChangedRegion());

                                if(unstable.Count > 1)	//	Swallowing violation detected
                                {
                                    if(DialogResult.OK==MessageBox.Show(this.Owner,
                                        "Swallow unstable polygons with the active polygon?",
                                        "Pixel exclusivity violation detected.",MessageBoxButtons.OKCancel))
                                    {
                                        //	Check to make sure that all polygons can be swallowed.
                                        for(int i=0;i<unstable.Count;i++)
                                        {
                                            if(unstable[i] != actPoly)		//	If the unstable polygon is not the active polygon
                                            {
                                                if(unstable[i].Owner == actPoly.Owner)	//	If the unstable and active polygons do not have the same owner.
                                                {
                                                    stable = false;
                                                    toSwallow.Clear();
                                                    MessageBox.Show(this.Owner,"Swallowing operation cannot continue.  The polygon "+ unstable[i].ToString() +" cannot be swallowed" + 
														    " by the active polygon because both polygons are part of the same object.","Requested action was not executed.");
                                                }

                                                if(stable && unstable[i].SharesVertexWith(actPoly))
                                                {
                                                    stable = false;
                                                    toSwallow.Clear();
                                                    MessageBox.Show(this.Owner,"Swallowing operation cannot continue.  The polygon "+ unstable[i].ToString() +" cannot be swallowed" + 
														    " by the active polygon because the polygons share at least one common vertex.","Requested action was not executed.");
                                                }

                                                if(stable && unstable[i].Swallowed.Contains(actPoly))
                                                {
                                                    stable = false;
                                                    toSwallow.Clear();
                                                    MessageBox.Show(this.Owner,"Swallowing operation cannot continue.  The polygon "+ unstable[i].ToString() +" cannot be swallowed" + 
														    " by the active polygon it has already swallowed the active polygon.","Requested action was not executed.");
                                                }
                                                if(stable && unstable[i].SwallowedBy!=null)
                                                {
                                                    stable = false;
                                                    toSwallow.Clear();
                                                    MessageBox.Show(this.Owner,"Swallowing operation cannot continue.  The polygon "+ unstable[i].ToString() +" cannot be swallowed" + 
														    " because it is already swallowed by " +unstable[i].SwallowedBy.ToString(),"Requested action was not executed.");
                                                }
                                                if(stable && unstable[i].Swallowed.Contains(actPoly))		//	And if the active polygon has not already swallowed the unstable polygon
                                                {
                                                    //	Swallowing operation cannot continue.  The polygon in question is not swallowable.
                                                    stable = false;
                                                    toSwallow.Clear();
                                                    MessageBox.Show(this.Owner,"Swallowing operation cannot continue.  The polygon "+ unstable[i].ToString() +" cannot be swallowed." + 
														    "It is already swallowing the active polygon.","Requested action could not be executed.");
                                                }
                                                if(stable)
                                                {
                                                    toSwallow.Add(unstable[i]);
                                                }
                                            }
                                        }

                                        //	Swallow.
                                        for(int i=0;i<toSwallow.Count;i++)
                                        {
                                            //	Swallowing requires doubly linking two lists.
                                            actPoly.Swallowed.Add(toSwallow[i]);
                                            toSwallow[i].SwallowedBy = actPoly;
                                            //	Swallowing means invalidating the toSwallow[i] polygon.
                                            Owner.Pb.Invalidate(Owner.InvPbRect(Owner.ImgToPbRect(toSwallow[i].GetBoundingRect(1))));
                                        }
                                    }
                                    else
                                    {	//	Don't swallow, Undo().
                                        stable = false;
                                    }
                                }
                            }
                            Cmd_Link cmd = null;
                            if( actCon==null )
                                cmd = new Cmd_Link(Glider, actPoly, toSwallow, toUnswallow, actPoly.ValidateEdges());
                            else
                                cmd = new Cmd_Link(Glider, actCon, toSwallow, toUnswallow, actPoly.ValidateEdges());
                            //	Swallow and unswallow for Undo purposes.
                            //macro.Add(toSwallow);
                            //macro.Add(toUnswallow);
                            //	Edge validation for Undo purposes
                            //macro.Add(Owner.Opd.ActivePoly.ValidateEdges());
                            //Owner.UndoStack.Add(macro);
                            Owner.UndoStack.Add(cmd);
                            //Owner.RedoStack.Clear();
                            Owner.RedoStack.Clear();
                            //	Automatically undo the action of unstable.
                            if(!stable)
                            {
                                Owner.Undo();
                                Owner.RedoStack.Clear();
                            }
                        }
                    }
                }
            }
            #endregion
            #region Not Link Mode (OnMouseDown)
            else if(NewBridge==null)
            {
                ActiveAtFirstMouseDown = Owner.Opd.ActiveThing;

                if(e.Button==MouseButtons.Left)
                {
                    Cursor.Current = Cursors.Cross;

                    if(this.ShiftKeyIsDown || this.CtrlKeyIsDown)
                    {
                        if(DrawPts[0])
                        {
                            MovingPathPt = true;
                            ImgMovedPathPt = ImgLeg[0];						//	Trace the ending point.
                            _ImgMovedPathPt.MimicValuesOf(ImgMovedPathPt);
                            //	Record the starting point of the movement.
                            ImgMovedPathPtStart.X = _ImgMovedPathPt.X;
                            ImgMovedPathPtStart.Y = _ImgMovedPathPt.Y;
                            //	Update ImgLeg[0] to be the next point over (because ImgMovedPathPt has focus now).
                            if(actPoly != null)
                            {
                                if(actCon==null)
                                {
                                    if(actPoly.Count > 2)
                                    {
                                        int im = actPoly.IndexOf(ImgLeg[0]);
                                        int prev = LastInd(actPoly.Count,im);
                                        if(actPoly[prev]==ImgLeg[1])
                                            ImgLeg[0] = actPoly[NextInd(actPoly.Count,im)];
                                        else
                                            ImgLeg[0] = actPoly[prev];
                                        PbLeg[0].X = Owner.ImgToPbX(ImgLeg[0].X);
                                        PbLeg[0].Y = Owner.ImgToPbX(ImgLeg[0].Y);
                                    }
                                }
                                else
                                {
                                    if(actCon.Count > 1)
                                    {
                                        int im = actCon.IndexOf(ImgLeg[0]);
                                        int prev = im-1;
                                        int next = im+1;
                                        if(prev>=0 && next>=actCon.Count)
                                            ImgLeg[0] = actCon[prev];
                                        else if(prev<0 && next<actCon.Count)
                                            ImgLeg[0] = actCon[next];
                                        else if(actCon[prev]==ImgLeg[1])
                                            ImgLeg[0] = actCon[next];
                                        else if(actCon[next]==ImgLeg[1])
                                            ImgLeg[0] = actCon[prev];
                                        PbLeg[0].X = Owner.ImgToPbX(ImgLeg[0].X);
                                        PbLeg[0].Y = Owner.ImgToPbX(ImgLeg[0].Y);
                                    }
                                }
                            }

                            //	Record the first point of movement.
                            ImgMovedPathPt.X = Owner.PbToImgX((float)PbStylus.X);
                            ImgMovedPathPt.Y = Owner.PbToImgY((float)PbStylus.Y);
                        }
                    }
                    else
                    {
                        //	Set the mode to true.
                        MovingPathPt = AddingPathPt = true;
                        Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetPtDrawRect(PbStylus,RADIUS+1)));

                        //	Start the new point.
                        ImgMovedPathPt = new VertexF(
                            Owner.PbToImgX((float)PbStylus.X),
                            Owner.PbToImgY((float)PbStylus.Y),
                            new PolyFarray(true),new ContourFarray(true));

                        bool notFormed = actPoly==null || (Owner.CurrentTool==ToolType.Contour && actCon==null);
                        if(!notFormed)
                        {
                            if(actCon==null)
                                notFormed = actPoly.Count < 2;
                            else
                                notFormed = actCon.Count < 2;
                        }
                        //	Get back and front points.
                        if(notFormed)	//	No points were being drawn.  Therefore, some initialization must take place.
                        {
                            CategoryNode actCn = Owner.Opd.ActiveCategory;
                            ParsedObject actObj = Owner.Opd.ActiveObject;

                            if(actObj==null)	// Create an active object since one does not exist.
                            {
                                actCn.Objects.Add(new ParsedObject(Owner.Opd.ObjectCt++,actCn));
                                actCn.ActiveObjectInd = 0;
                                actObj = Owner.Opd.ActiveObject;
                            }
                            if(actPoly==null)	// Create an active polygon since one does not exist.
                            {
                                actObj.Polygons.Add(new PolygonF(actObj));
                                actObj.ActivePolyInd = 0;
                                actPoly = Owner.Opd.ActivePoly;
                            }
                            if(Owner.CurrentTool==ToolType.Contour && actCon==null)
                            {
                                actPoly.Contours.Add(new ContourF(actPoly));
                                actPoly.ActiveContourInd=0;
                                actCon = Owner.Opd.ActiveContour;
                            }

                            //	Insert the point into the correct slot.
                            if(actCon==null)
                            {
                                ImgMovedPathPt.Polygons.Add(actPoly);		//	Tie from the VertexF side
                                actPoly.Add(ImgMovedPathPt);			//	And then from the PolygonF side
                            }
                            else
                            {
                                ImgMovedPathPt.Contours.Add(actCon);		//	Tie from the VertexF side
                                actCon.Add(ImgMovedPathPt);				//	Insert at end
                            }
                        }
                        else
                        {
                            //	Check to see if a contour is being extended at the end
                            if(actCon!=null && !DrawPts[1])
                            {
                                ImgMovedPathPt.Contours.Add(actCon);
                                //	Insert the point at the end of the path where it belongs.
                                if(actCon[0]==ImgLeg[0])
                                    actCon.Insert(0,ImgMovedPathPt);
                                else // actCon[actCon.Count-1]==ImgLeg[0]
                                    actCon.Add(ImgMovedPathPt);
                            }
                            else
                            {
                                //	There are two vertices adjacent.  Their common owners will be joined with the ImgMovedPathPt.
                                int j,ii,jj,next;
                                PathF path;
                                //	Append its owners onto the new PolyPt.
                                for(int i=0;i<ImgLeg[0].Polygons.Count;i++)
                                {
                                    path = ImgLeg[0].Polygons[i];
                                    j=ImgLeg[1].Polygons.IndexOf(path);
                                    if(j>=0)
                                    {
                                        //	The PolygonF must be attached in two ways:
                                        //	(1):	The owner must be added to ImgMovedPathPt list of owners.
                                        ImgMovedPathPt.Polygons.Add(path);
                                        //	(2):	The ImgMovedPathPt must be inserted into each owner at the correct place.
                                        //		Compute the insert index (ii)
                                        ii = path.IndexOf(ImgLeg[0]);
                                        next = ii+1;
                                        if(next > path.Count-1 && path.GetType()==typeof(PolygonF))
                                            next = 0;
                                        jj = path.IndexOf(ImgLeg[1]);
                                        if(jj==next)	//	Insert after the current ImgLeg[0].
                                            ii=next;
                                        //		Finally attach the ImgMovedPathPt into the owner polygon at the correct place.
                                        path.Insert(ii,ImgMovedPathPt);	//	ii is the insert ind.
                                    }
                                }
                                for(int i=0;i<ImgLeg[0].Contours.Count;i++)
                                {
                                    path = ImgLeg[0].Contours[i];
                                    j=ImgLeg[1].Contours.IndexOf(path);
                                    if(j>=0)
                                    {
                                        //	The PolygonF must be attached in two ways:
                                        //	(1):	The owner must be added to ImgMovedPathPt list of owners.
                                        ImgMovedPathPt.Contours.Add(path);
                                        //	(2):	The ImgMovedPathPt must be inserted into each owner at the correct place.
                                        //		Compute the insert index (ii)
                                        ii = path.IndexOf(ImgLeg[0]);
                                        next = ii+1;
                                        if(next > path.Count-1 && path.GetType()==typeof(PolygonF))
                                            next = 0;
                                        jj = path.IndexOf(ImgLeg[1]);
                                        if(jj==next)	//	Insert after the current ImgLeg[0].
                                            ii=next;
                                        //		Finally attach the ImgMovedPathPt into the owner polygon at the correct place.
                                        path.Insert(ii,ImgMovedPathPt);	//	ii is the insert ind.
                                    }
                                }
                            }
                        }
                        //	Extract the Pb PointF[] information for all the polys because a new vertex was added
                        //	and there is possibly a new polygon.
                        UpdateInactivePaths();
                    }

                    //	Adjust the way the leg is highlighted.
                    UpdateVertexDraw();
                }
            }
            #endregion

        }
        public void OnMouseUp(object sender,System.Windows.Forms.MouseEventArgs e)
        {
            _PbStylus = PbStylus;
            PbStylus.X = e.X;
            PbStylus.Y = e.Y;
            PathF pf;	//	Temporary local variable in the code below, used at many different spots locally.

            ContourF actCon = null;
            if(Owner.CurrentTool==ToolType.Contour)
                actCon = Owner.Opd.ActiveContour;
            PolygonF actPoly = this.Owner.Opd.ActivePoly;
            ArrayList macro = new ArrayList();

            if(!LinkMode)	//	There is no OnMouseUp processing for Link Mode, only normal mode.
            {
                if(e.Button==MouseButtons.Left)
                {
                    if(NewBridge!=null)
                    {
                        #region A new bridge was just built.
                        if(NewBridge.Vf1!=NewBridge.Vf2)
                        {
                            ParsedObject activeObj = Owner.Opd.ActiveObject;
                            OcclusionBridge destroyed = null;
                            for(int i=0;i<activeObj.Bridges.Count;i++)
                            {
                                destroyed = activeObj.Bridges[i];
                                if(destroyed.Vf1==NewBridge.Vf2 || destroyed.Vf2==NewBridge.Vf2)
                                {
                                    activeObj.Bridges.RemoveAt(i);
                                    break;
                                }
                                destroyed = null;
                            }

                            activeObj.Bridges.Add(NewBridge);

                            macro.Add(130);
                            macro.Add(NewBridge);
                            macro.Add(destroyed);
                            macro.Add(Owner.Opd.ActivePoly.ValidateEdges());

                            Owner.UndoStack.Add(macro);
                            Owner.RedoStack.Clear();

                            NewBridge=null;
                        }
                        #endregion
                    }
                    else if(MovingPathPt)
                    {
                        #region Shift & Left-OnMouseUp (Delete 102)
                        if(ShiftKeyIsDown)
                        {
                            Rectangle clipRect = new Rectangle(0,0,0,0);
                            PolygonF changedRegion = new PolygonF(null);

                            if(ImgMovedPathPt.Polygons.Count>0)
                                pf = ImgMovedPathPt.Polygons[0];
                            else
                                pf = ImgMovedPathPt.Contours[0];

                            //	Just used for computing a bounding rect of points, not actually a polygon.
                            changedRegion.Add(ImgMovedPathPt);
                            int mid = pf.IndexOf(ImgMovedPathPt);
                            if(mid<pf.Count-1 || pf.GetType()==typeof(PolygonF))
                                changedRegion.Add(pf[NextInd(pf.Count,mid)]);
                            if(!AddingPathPt)
                                changedRegion.Add(new VertexF(ImgMovedPathPtStart.X,ImgMovedPathPtStart.Y,null,null));
                            if(mid > 0 || pf.GetType()==typeof(PolygonF))
                                changedRegion.Add(pf[LastInd(pf.Count,mid)]);

                            if(DrawPts[1])
                            {
                                clipRect = changedRegion.GetBoundingRect(0);
                                Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(Owner.ImgToPbRect(clipRect),PathTool.RADIUS+1)));
                            }
                            else
                            {
                                Owner.Pb.Invalidate(Owner.InvPbRect(Owner.ImgToPbRect(VertexF.GetBoundingRect(ImgMovedPathPt,RADIUS+1))));
                                Owner.Pb.Invalidate(Owner.InvPbRect(Owner.ImgToPbRect(VertexF.GetBoundingRect(_ImgMovedPathPt,RADIUS+1))));
                                if(actPoly.Count == 2 && actCon==null)
                                    Owner.Pb.Invalidate(Owner.InvPbRect(Owner.ImgToPbRect(VertexF.GetBoundingRect(actPoly[0],actPoly[1],RADIUS+1))));
                                else if(actCon!=null && actCon.Count == 2)
                                    Owner.Pb.Invalidate(Owner.InvPbRect(Owner.ImgToPbRect(VertexF.GetBoundingRect(actCon[0],actCon[1],RADIUS+1))));
                            }

                            //	Remove the vertex.
                            int[] polyIndices,conIndices;
                            ImgMovedPathPt.RemoveFromAllOwners(out polyIndices,out conIndices);
                            ContourFarray cons;
                            PolyFarray polys;
                            ImgMovedPathPt.RemoveAllOwners(out polys,out cons);

                            bool stable = true;
                            int i;

                            //	Check for a polygon leg-crossing violation
                            for(i=0;i<polys.Count;i++)
                                if(((PolygonF)polys[i]).IntersectsSelf())
                                    stable = false;

                            //	Accumulate a list of swallowed polygons (for Undo).
                            PolyFarray toSwallow = new PolyFarray(true);

                            //	Check for a swallowing violation
                            if(stable)
                            {
                                PolygonFlist unstable = Owner.Opd.RegionIsStable(changedRegion);

                                if(unstable.Count > 1)	//	Swallowing violation detected
                                {
                                    if(DialogResult.OK==MessageBox.Show(this.Owner,"Swallow unstable polygons with the active polygon?",
                                        "Pixel exclusivity violation detected.",MessageBoxButtons.OKCancel))
                                    {	//	Check to make sure that all polygons can be swallowed.
                                        for(i=0;i<unstable.Count;i++)
                                        {
                                            if(unstable[i] != actPoly)		//	If the unstable polygon is not the active polygon
                                            {
                                                if(unstable[i].Owner == actPoly.Owner)	//	If the unstable and active polygons do not have the same owner.
                                                {
                                                    stable = false;
                                                    toSwallow.Clear();
                                                    MessageBox.Show(this.Owner,"Swallowing operation cannot continue.  The polygon "+ unstable[i].ToString() +" cannot be swallowed" + 
														    " by the active polygon because both polygons are part of the same object.","Requested action was not executed.");
                                                }

                                                if(stable && unstable[i].SharesVertexWith(actPoly))
                                                {
                                                    stable = false;
                                                    toSwallow.Clear();
                                                    MessageBox.Show(this.Owner,"Swallowing operation cannot continue.  The polygon "+ unstable[i].ToString() +" cannot be swallowed" + 
														    " by the active polygon because the polygons share at least one common vertex.","Requested action was not executed.");
                                                }
                                                if(stable && unstable[i].Swallowed.Contains(actPoly))
                                                {
                                                    stable = false;
                                                    toSwallow.Clear();
                                                    MessageBox.Show(this.Owner,"Swallowing operation cannot continue.  The polygon "+ unstable[i].ToString() +" cannot be swallowed" + 
														    " by the active polygon because it has already swallowed the active polygon.","Requested action was not executed.");
                                                }
                                                if(stable && unstable[i].SwallowedBy!=null)
                                                {
                                                    stable = false;
                                                    toSwallow.Clear();
                                                    MessageBox.Show(this.Owner,"Swallowing operation cannot continue.  The polygon "+ unstable[i].ToString() +" cannot be swallowed" + 
														    " because it is already swallowed by " +unstable[i].SwallowedBy.ToString(),"Requested action was not executed.");
                                                }
                                                if(stable && unstable[i].Swallowed.Contains(actPoly))		//	And if the active polygon has not already swallowed the unstable polygon
                                                {
                                                    //	Swallowing operation cannot continue.  The polygon in question is not swallowable.
                                                    stable = false;
                                                    toSwallow.Clear();
                                                    MessageBox.Show(this.Owner,"Swallowing operation cannot continue.  The polygon "+ unstable[i].ToString() +" cannot be swallowed." + 
														    "It is already swallowing the active polygon.","Requested action could not be executed.");
                                                }
                                                if(stable)
                                                {
                                                    toSwallow.Add(unstable[i]);
                                                }
                                            }
                                        }

                                        //	Swallow.
                                        for(i=0;i<toSwallow.Count;i++)
                                        {
                                            //	Swallowing requires doubly linking two lists.
                                            actPoly.Swallowed.Add(toSwallow[i]);
                                            toSwallow[i].SwallowedBy = actPoly;
                                            //	Swallowing means invalidating the toSwallow[i] polygon.
                                            Owner.Pb.Invalidate(Owner.InvPbRect(Owner.ImgToPbRect(toSwallow[i].GetBoundingRect(1))));
                                        }
                                    }
                                    else
                                    {	//	Don't swallow, Undo().
                                        stable = false;
                                    }
                                }
                            }
                            else if(stable && actCon!=null)
                            {
                                if(actCon.IntersectsSelf())
                                {
                                    stable = false;
                                    MessageBox.Show(this.Owner,"The point cannot be deleted because the resulting contour intersects itself.");
                                }
                                if(actCon.IntersectsWithoutJoining(actPoly))
                                {
                                    stable = false;
                                    MessageBox.Show(this.Owner,"The point cannot be deleted because the resulting contour intersects its parent polygon.");
                                }
                            }

                            EdgeGroupArray ega = null;
                            if(actCon==null)
                                ega = actPoly.ValidateEdges();

                            //	Deletes a VertexF from all polygons
                            ImgMovedPathPt.X  = ImgMovedPathPtStart.X;
                            ImgMovedPathPt.Y = ImgMovedPathPtStart.Y;
                            Cmd_DeleteVertex cmd = new Cmd_DeleteVertex(ImgMovedPathPt,actPoly,Owner.Opd.ActivePoly,toSwallow,null,
                                polys,cons,polyIndices,conIndices,ega,actPoly.Owner.ValidateBridges());


                            //	( VertexF vf, ArrayList polys, int[] index, object activeFirst, object activeLast,
                            //		toSwallow, toUnswallow, edgeValidationResult )
                            /*
                            ArrayList macro = new ArrayList();
                            macro.Add(102);
                            macro.Add(ImgMovedPathPt);
                            macro.Add(oldOwners);
                            macro.Add(oldIndexes);
                            macro.Add(this.ActiveAtFirstMouseDown);
                            macro.Add(Owner.Opd.ActiveThing);
                            macro.Add(toSwallow);
                            macro.Add(null);	//	To unswallow
                            if(actCon==null)
                                macro.Add(actPoly.ValidateEdges());
                            else
                                macro.Add(null);
                            macro.Add(actPoly.Owner.ValidateBridges());
                            */

                            //  Proceed with deletion
                            if(stable && DrawPts[1])
                            {
                                //	Paint any Inactive PixelTaggers and Bitmaps using the changedRegion[]
                                for(i=0;i<polys.Count;i++)
                                {
                                    pf = polys[i];
                                    ((PolygonF)pf).AfterRemoveVertexF(polyIndices[i],ImgMovedPathPt,GetBitmap(pf),GetColor(pf));
                                }
                                //Owner.UndoStack.Add(macro);
                                Owner.UndoStack.Add(cmd);
                                Owner.RedoStack.Clear();
                            }
                            //  Cancel deletion
                            else if(!stable)
                            {
                                if(toSwallow != null)
                                {
                                    for(i=0;i<toSwallow.Count;i++)
                                    {
                                        actPoly.Swallowed.Remove(toSwallow[i]);
                                        toSwallow[i].SwallowedBy = null;
                                    }
                                }
                                for(i=0;i<polys.Count;i++)
                                {
                                    polys[i].Insert(polyIndices[i],ImgMovedPathPt);
                                    if(!ImgMovedPathPt.Polygons.Contains(polys[i]))
                                        ImgMovedPathPt.Polygons.Add(polys[i]);
                                }
                                for(i=0;i<cons.Count;i++)
                                {
                                    cons[i].Insert(conIndices[i],ImgMovedPathPt);
                                    if(!ImgMovedPathPt.Contours.Contains(cons[i]))
                                        ImgMovedPathPt.Contours.Add(cons[i]);
                                }
                                Owner.Ptool.UpdateVertexDraw();
								Owner.Ptool.UpdateInactivePaths();
                            }
                        }
                        #endregion
                        #region Left-OnMouseUp (Add 101 and Move 104)
                        else		//	Shift key is not down.  We are either adding or moving a point.
                        {
                            UpdateVertexDraw();

                            Rectangle clipRect = new Rectangle(0,0,0,0);
                            PolygonF changedRegion = new PolygonF(null);
                            PolyFarray toSwallow = new PolyFarray(true);
                            PolyFarray toUnswallow = new PolyFarray(true);
                            bool stable = true;

                            //	Make sure the contour point is inside its polygon
                            if(actCon!=null)
                            {
                                if(!actCon.PolyOwner.Contains(ImgMovedPathPt) && actCon.PolyOwner.InPoly(ImgMovedPathPt.X,ImgMovedPathPt.Y)<=0)
                                {
                                    stable = false;
                                    MessageBox.Show(this.Owner,"All vertices in the active contour must lie within the active polygon.","Action canceled.");
                                }
                            }

                            Command cm=null;
                            PolyFarray polyOwners=null;
                            ContourFarray conOwners=null;

                            if((actCon==null && actPoly.Count > 2) || (actCon!=null && actCon.Count>2))
                            {
                                int i=1;
                                if(ImgMovedPathPt.Polygons.Count>0)
                                    pf = ImgMovedPathPt.Polygons[0];
                                else
                                    pf = this.ImgMovedPathPt.Contours[0];

                                //	Just used for computing a bounding rect of points, not actually a polygon.
                                changedRegion.Add(ImgMovedPathPt);
                                int mid = pf.IndexOf(ImgMovedPathPt);
                                if(mid<pf.Count-1 || pf.GetType()==typeof(PolygonF))
                                    changedRegion.Add(pf[NextInd(pf.Count,mid)]);
                                if(!AddingPathPt)
                                    changedRegion.Add(new VertexF(ImgMovedPathPtStart.X,ImgMovedPathPtStart.Y,null,null));
                                if(mid > 0 || pf.GetType()==typeof(PolygonF))
                                    changedRegion.Add(pf[LastInd(pf.Count,mid)]);

                                clipRect = changedRegion.GetBoundingRect(0);
                                Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(Owner.ImgToPbRect(clipRect),PathTool.RADIUS+1)));

                                if(AddingPathPt)	//	A point is being added
                                {
                                    polyOwners = new PolyFarray(true);
                                    conOwners = new ContourFarray(true);
                                    int[] polyInd = new int[ImgMovedPathPt.Polygons.Count];
                                    int[] conInd = new int[ImgMovedPathPt.Contours.Count];
                                    for(i=0;i<ImgMovedPathPt.Polygons.Count;i++)
                                    {
                                        polyOwners.Add(ImgMovedPathPt.Polygons[i]);
                                        polyInd[i] = ImgMovedPathPt.Polygons[i].IndexOf(ImgMovedPathPt);
                                    }
                                    for(i=0;i<ImgMovedPathPt.Contours.Count;i++)
                                    {
                                        conOwners.Add(ImgMovedPathPt.Contours[i]);
                                        conInd[i] = ImgMovedPathPt.Contours[i].IndexOf(ImgMovedPathPt);
                                    }
                                    cm = new Cmd_AddVertex(
                                        ImgMovedPathPt,actPoly,actPoly,toSwallow,toUnswallow,null,null,
                                        polyOwners,conOwners,polyInd,conInd,null,null);
                                    /*
                                    //	Add vertex to the active polygon ( VertexF vf, PolygonFarray polys, int[] index, object activeFirst, object activeLast)
                                    macro.Add(101);
                                    macro.Add(ImgMovedPathPt);
                                    macro.Add(addOwners);
                                    macro.Add(addIndexes);
                                    macro.Add(this.ActiveAtFirstMouseDown);
                                    if(actCon==null)
                                        macro.Add(Owner.Opd.ActiveThing);
                                    else
                                        macro.Add(actCon);
                                    */
                                }
                                else	//	The point is being moved.
                                {
                                    //	Revert to the starting state in order to clear bitmaps and pixeltaggers.
                                    PointF moveTo = new PointF(ImgMovedPathPt.X,ImgMovedPathPt.Y);

                                    //	Adjust the Pb tables for each polygon and contour.
                                    int ind;
                                    for(i=0;i<ImgMovedPathPt.Polygons.Count;i++)
                                    {
                                        pf = ImgMovedPathPt.Polygons[i];
                                        ind = pf.IndexOf(ImgMovedPathPt);
										pf.PbPath[ind] = Owner.ImgToPb(ImgMovedPathPt.PointF);
                                    }
                                    for(i=0;i<ImgMovedPathPt.Contours.Count;i++)
                                    {
                                        pf = ImgMovedPathPt.Contours[i];
                                        ind = pf.IndexOf(ImgMovedPathPt);
										pf.PbPath[ind] = Owner.ImgToPb(ImgMovedPathPt.PointF);
                                    }

                                    //	Moves the location of a VertexF (in x and y coordinates).
                                    //	( VertexF vf, PointF from, PointF to )
                                    cm = new Cmd_MoveVertex(ImgMovedPathPt,ImgMovedPathPtStart,moveTo,actPoly,toSwallow,toUnswallow);
                                    /*
                                    macro.Add(104);
                                    macro.Add(ImgMovedPathPt);
                                    macro.Add(ImgMovedPathPtStart);
                                    macro.Add(moveTo);
                                    */
                                }
                            }
                            else	//	actPoly.Count <= 2
                            {
                                //  Invalidate the vertices old and new locations
                                Owner.Pb.Invalidate(Owner.InvPbRect(Owner.ImgToPbRect(VertexF.GetBoundingRect(ImgMovedPathPt,RADIUS+1))));
                                Owner.Pb.Invalidate(Owner.InvPbRect(Owner.ImgToPbRect(VertexF.GetBoundingRect(_ImgMovedPathPt,RADIUS+1))));
                                //  Active Poly (active contour is null)
                                if(actCon==null && actPoly.Count == 2)
                                    Owner.Pb.Invalidate(Owner.InvPbRect(Owner.ImgToPbRect(VertexF.GetBoundingRect(actPoly[0],actPoly[1],RADIUS+1))));
                                //  Active Contour
                                else if(actCon!=null && actCon.Count == 2)
                                    Owner.Pb.Invalidate(Owner.InvPbRect(Owner.ImgToPbRect(VertexF.GetBoundingRect(actCon[0],actCon[1],RADIUS+1))));
                                if(AddingPathPt)
                                {
                                    //	Generate pflist, a list of unstable polygons.
                                    PolygonFlist pflist = Owner.Opd.PolysContainingPoint(ImgMovedPathPt.X,ImgMovedPathPt.Y,false);
                                    int ct = 0;
                                    while(pflist.Count > ct)
                                    {
                                        if(pflist[ct].Swallowed.Contains(actPoly))
                                            pflist.RemoveAt(ct);
                                        else
                                            ct++;
                                    }
                                    DialogResult dr = DialogResult.OK;
                                    if(pflist.Count>0 && actPoly.SwallowedBy != null && actPoly.SwallowedBy != pflist[0])
                                    {
                                        MessageBox.Show(this.Owner,"Point cannot be added.  A pixel exclusivity violation was detected, but no corrective action can be taken"
											    +" because the active polygon is already swallowed.","Requested action was not executed.");
                                        dr = DialogResult.Cancel;
                                    }
                                    if(dr==DialogResult.OK && pflist.Count>0)
                                    {
                                        dr = MessageBox.Show(this.Owner,
                                            "Feed the active polygon to the owner of these pixels?",
                                                "Pixel exclusivity violation detected.",MessageBoxButtons.OKCancel);
                                    }
                                    if(dr==DialogResult.OK)
                                    {
                                        PolygonF toBeUnswallowedBy = actPoly.SwallowedBy;
                                        PolygonF toBeSwallowedBy = null;
                                        if(pflist.Count > 0)
                                        {
                                            toBeSwallowedBy = pflist[0];
                                            pflist[0].Swallowed.Add(actPoly);
                                            actPoly.SwallowedBy = pflist[0];
                                        }
                                        //	Add vertex to the active polygon ( VertexF vf, ArrayList polys, int[] index, object activeFirst, object activeLast)
                                        //PathFarray owners = new PathFarray(true);
                                        int i;
                                        polyOwners = new PolyFarray(true);
                                        conOwners = new ContourFarray(true);
                                        int[] polyInd = new int[ImgMovedPathPt.Polygons.Count];
                                        int[] conInd = new int[ImgMovedPathPt.Contours.Count];
                                        for(i=0;i<ImgMovedPathPt.Polygons.Count;i++)
                                        {
                                            polyOwners.Add(ImgMovedPathPt.Polygons[i]);
                                            polyInd[i] = ImgMovedPathPt.Polygons[i].IndexOf(ImgMovedPathPt);
                                        }
                                        for(i=0;i<ImgMovedPathPt.Contours.Count;i++)
                                        {
                                            conOwners.Add(ImgMovedPathPt.Contours[i]);
                                            conInd[i] = ImgMovedPathPt.Contours[i].IndexOf(ImgMovedPathPt);
                                        }
                                        /*
                                        macro.Add(101);
                                        macro.Add(ImgMovedPathPt);
                                        macro.Add(owners);
                                        macro.Add(index);
                                        macro.Add(this.ActiveAtFirstMouseDown);
                                        macro.Add(Owner.Opd.ActiveThing);
                                        */
                                        cm = new Cmd_AddVertex(
                                            ImgMovedPathPt,actPoly,actPoly,toSwallow,toUnswallow,toBeSwallowedBy,toBeUnswallowedBy,
                                            polyOwners,conOwners,polyInd,conInd,null,null);
                                    }
                                }
                                else	//	MovingPathPt
                                {
                                    //	Generate pflist, a list of unstable polygons.
                                    PolygonFlist pflist = Owner.Opd.PolysContainingPoint(ImgMovedPathPt.X,ImgMovedPathPt.Y,false);
                                    int ct = 0;
                                    while(pflist.Count > ct)
                                    {
                                        if(pflist[ct].Swallowed.Contains(actPoly))
                                            pflist.RemoveAt(ct);
                                        else
                                            ct++;
                                    }
                                    DialogResult dr = DialogResult.OK;
                                    if(pflist.Count>0 && actPoly.SwallowedBy != null && actPoly.SwallowedBy != pflist[0])
                                    {
                                        MessageBox.Show(this.Owner,"Point cannot be added.  A pixel exclusivity violation was detected, but no corrective action can be taken"
											    +" because the active polygon is already swallowed.","Requested action was not executed.");
                                        dr = DialogResult.Cancel;
                                    }
                                    if(dr==DialogResult.OK && pflist.Count>0)
                                    {
                                        dr = MessageBox.Show(this.Owner,
                                            "Feed the active polygon to the owner of these pixels?","Pixel exclusivity violation detected.",MessageBoxButtons.OKCancel);
                                    }
                                    if(dr==DialogResult.OK)
                                    {
                                        if(pflist.Count > 0)
                                        {
                                            pflist[0].Swallowed.Add(actPoly);
                                            actPoly.SwallowedBy = pflist[0];
                                        }
                                        //	Moves the location of a VertexF (in x and y coordinates).
                                        //	( VertexF vf, PointF from, PointF to )
                                        PointF moveTo = new PointF(ImgMovedPathPt.X,ImgMovedPathPt.Y);

                                        //macro.Add(104);
                                        //macro.Add(ImgMovedPathPt);
                                        //macro.Add(ImgMovedPathPtStart);
                                        //macro.Add(moveTo);
                                        cm = new Cmd_MoveVertex(ImgMovedPathPt,ImgMovedPathPtStart,moveTo,actPoly,toSwallow,toUnswallow);
                                    }
                                }
                            }

                            //	Check for a leg-crossing violation.
                            for(int i=0;i<ImgMovedPathPt.Polygons.Count;i++)
                                if(ImgMovedPathPt.Polygons[i].IntersectsSelf())
                                    stable = false;

                            //	Check for a swallowing violation
                            if(stable)
                            {
                                PolygonFlist unstable = Owner.Opd.RegionIsStable(changedRegion);

                                if(unstable.Count > 1)	//	Swallowing violation detected
                                {
                                    if(DialogResult.OK==MessageBox.Show(this.Owner,"Swallow unstable polygons with the active polygon?","Pixel exclusivity violation detected.",MessageBoxButtons.OKCancel))
                                    {	//	Check to make sure that all polygons can be swallowed.
                                        for(int i=0;i<unstable.Count;i++)
                                        {
                                            if(unstable[i] != actPoly)		//	If the unstable polygon is not the active polygon
                                            {
                                                if(unstable[i].Owner == actPoly.Owner)	//	If the unstable and active polygons do not have the same owner.
                                                {
                                                    stable = false;
                                                    toSwallow.Clear();
                                                    MessageBox.Show(this.Owner,"Swallowing operation cannot continue.  The polygon "+ unstable[i].ToString() +" cannot be swallowed" + 
														    " by the active polygon because both polygons are part of the same object.","Requested action was not executed.");
                                                }
                                                if(stable && unstable[i].SharesVertexWith(actPoly))
                                                {
                                                    stable = false;
                                                    toSwallow.Clear();
                                                    MessageBox.Show(this.Owner,"Swallowing operation cannot continue.  The polygon "+ unstable[i].ToString() +" cannot be swallowed" + 
														    " by the active polygon because the polygons share at least one common vertex.","Requested action was not executed.");
                                                }
                                                if(stable && unstable[i].Swallowed.Contains(actPoly))
                                                {
                                                    stable = false;
                                                    toSwallow.Clear();
                                                    MessageBox.Show(this.Owner,"Swallowing operation cannot continue.  The polygon "+ unstable[i].ToString() +" cannot be swallowed" + 
														    " by the active polygon because it has already swallowed the active polygon.","Requested action was not executed.");
                                                }
                                                if(stable && unstable[i].SwallowedBy!=null)
                                                {
                                                    stable = false;
                                                    toSwallow.Clear();
                                                    MessageBox.Show(this.Owner,"Swallowing operation cannot continue.  The polygon "+ unstable[i].ToString() +" cannot be swallowed" + 
														    " because it is already swallowed by " +unstable[i].SwallowedBy.ToString(),"Requested action was not executed.");
                                                }
                                                if(stable && unstable[i].Swallowed.Contains(actPoly))		//	And if the active polygon has not already swallowed the unstable polygon
                                                {
                                                    //	Swallowing operation cannot continue.  The polygon in question is not swallowable.
                                                    stable = false;
                                                    toSwallow.Clear();
                                                    MessageBox.Show(this.Owner,"Swallowing operation cannot continue.  The polygon "+ unstable[i].ToString() +" cannot be swallowed." + 
														    "It is already swallowing the active polygon.","Requested action could not be executed.");
                                                }
                                                if(stable)
                                                {
                                                    toSwallow.Add(unstable[i]);
                                                }
                                            }
                                        }

                                        //	Swallow.
                                        for(int i=0;i<toSwallow.Count;i++)
                                        {
                                            //	Swallowing requires doubly linking two lists.
                                            actPoly.Swallowed.Add(toSwallow[i]);
                                            toSwallow[i].SwallowedBy = actPoly;
                                            //	Swallowing means invalidating the toSwallow[i] polygon.
                                            Owner.Pb.Invalidate(Owner.InvPbRect(Owner.ImgToPbRect(toSwallow[i].GetBoundingRect(1))));
                                        }
                                    }
                                    else
                                    {	//	Don't swallow, Undo().
                                        stable = false;
                                    }
                                }
                            }

                            if(stable && actCon!=null)
                            {
                                if(actCon.IntersectsSelf())
                                {
                                    stable = false;
                                    MessageBox.Show(this.Owner,"The action was canceled because the resulting contour intersects itself.");
                                }
                                if(actCon.IntersectsWithoutJoining(actPoly))
                                {
                                    stable = false;
                                    MessageBox.Show(this.Owner,"The action was canceled because the resulting contour intersects its parent polygon.");
                                }
                            }

                            if(cm!=null)	//	This follows adding and moving of points.
                            {
                                //macro.Add(toSwallow);
                                //macro.Add(toUnswallow);
                                //	Validate edges.
                                if(cm.GetType()==typeof(Cmd_AddVertex))	//	if adding (not for moving)
                                    if(actCon==null)
                                        ((Cmd_AddVertex)cm).DeleteCmd.Ega = actPoly.ValidateEdges();
                            }
                            else
                                stable = false;

                            if(stable)
                            {
                                Owner.UndoStack.Add(cm);
                                Owner.RedoStack.Clear();

                                //	Paint any Inactive PixelTaggers and Bitmaps using the changedRegion[]
                                //	If the midpoint of the old leg is inside of the acitve polygon
                                for(int i=0;i<ImgMovedPathPt.Polygons.Count;i++)
                                {
                                    pf = ImgMovedPathPt.Polygons[i];
                                    if(cm.GetType()==typeof(Cmd_AddVertex))
                                        ((PolygonF)pf).AfterAddVertexF(pf.IndexOf(ImgMovedPathPt),ImgMovedPathPt,GetBitmap(pf),GetColor(pf));
                                    else //moving
                                        ((PolygonF)pf).AfterMoveVertexF(pf.IndexOf(ImgMovedPathPt),this.ImgMovedPathPtStart,GetBitmap(pf),GetColor(pf));
                                }
                            }
							else if(cm!=null && cm.GetType()==typeof(Cmd_AddVertex))	//	UNSTABLE --> Delete the polygon point
                            {
                                /*
                                if(toSwallow != null)
                                {
                                    for(int i=0; i<toSwallow.Count; i++)
                                    {
                                        actPoly.Swallowed.Add(toSwallow[i]);
                                        toSwallow[i].SwallowedBy = actPoly;
                                    }
                                }
                                if(toUnswallow != null)
                                {
                                    for(int i=0; i<toUnswallow.Count; i++)
                                    {
                                        actPoly.Swallowed.Remove(toUnswallow[i]);
                                        toUnswallow[i].SwallowedBy = null;
                                    }
                                }
                                */

                                //  Clear the VertexF, the information still exists within cm.DeleteCmd
                                ImgMovedPathPt.Polygons = new PolyFarray(true);
                                ImgMovedPathPt.Contours = new ContourFarray(true);

                                //  Clear the polygon paths
                                for(int i=0;i<((Cmd_AddVertex)cm).DeleteCmd.Polygons.Count;i++)
                                {
                                    pf = ((Cmd_AddVertex)cm).DeleteCmd.Polygons[i];
                                    pf.RemoveAt(((Cmd_AddVertex)cm).DeleteCmd.PolyIndices[i]);
                                }
                                //  Clear the contour paths
                                for(int i=0;i<((Cmd_AddVertex)cm).DeleteCmd.Contours.Count;i++)
                                {
                                    pf = ((Cmd_AddVertex)cm).DeleteCmd.Contours[i];
                                    pf.RemoveAt(((Cmd_AddVertex)cm).DeleteCmd.ConIndices[i]);
                                }

                                //  Update drawing resources
                                UpdateVertexDraw();
								UpdateInactivePaths();
                            }
                            else	//	UNSTABLE --> Move the polygon point back
                            {
                                /*
                                if(toSwallow != null)
                                {
                                    for(int i=0; i<toSwallow.Count; i++)
                                    {
                                        actPoly.Swallowed.Add(toSwallow[i]);
                                        toSwallow[i].SwallowedBy = actPoly;
                                    }
                                }
                                if(toUnswallow != null)
                                {
                                    for(int i=0; i<toUnswallow.Count; i++)
                                    {
                                        actPoly.Swallowed.Remove(toUnswallow[i]);
                                        toUnswallow[i].SwallowedBy = null;
                                    }
                                }
                                */
                                bool oldMovingPathPt = MovingPathPt;
                                MovingPathPt = false;

                                ImgMovedPathPt.X = this.ImgMovedPathPtStart.X;
                                ImgMovedPathPt.Y = this.ImgMovedPathPtStart.Y;

                                PathF poly;
                                for(int i=0;i<ImgMovedPathPt.Polygons.Count;i++)
                                {
                                    poly = ImgMovedPathPt.Polygons[i];
                                    int ind = poly.IndexOf(ImgMovedPathPt);
									poly.PbPath[ind] = Owner.ImgToPb(ImgMovedPathPt.PointF);
                                }
                                for(int i=0;i<ImgMovedPathPt.Contours.Count;i++)
                                {
                                    poly = ImgMovedPathPt.Contours[i];
                                    int ind = poly.IndexOf(ImgMovedPathPt);
									poly.PbPath[ind] = Owner.ImgToPb(ImgMovedPathPt.PointF);
                                }
                                UpdateVertexDraw();
								UpdateInactivePaths();

                                MovingPathPt = oldMovingPathPt;
                            }
                        }
                        #endregion
                        if(actPoly.Count > 0)
                            Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetBoundingRect(actPoly.PbPath,PathTool.RADIUS+1)));
                    }
                }
            }
            MovingPathPt=false;
            AddingPathPt=false;
            Cursor.Current = Cursors.Cross;
        }
        public void OnKeyDown(object sender,System.Windows.Forms.KeyEventArgs e)
        {
            if(e.KeyCode==Keys.ControlKey)
            {
                CtrlKeyIsDown = true;

                for(int i=0;i<2;i++)
                    if(DrawPts[i])
                        Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetPtDrawRect(PbLeg[i],RADIUS+1)));
            }
            else if(e.KeyCode==Keys.ShiftKey)
                ShiftKeyIsDown = true;
        }
        public void OnKeyUp(object sender,System.Windows.Forms.KeyEventArgs e)
        {
            if(e.KeyCode==Keys.ControlKey)
            {
                CtrlKeyIsDown = false;
                for(int i=0;i<2;i++)
                    if(DrawPts[i])
                        Owner.Pb.Invalidate(Owner.InvPbRect(VertexF.GetPtDrawRect(PbLeg[i],RADIUS+1)));
            }
            else if(e.KeyCode==Keys.ShiftKey)
                ShiftKeyIsDown = false;
            else if(e.KeyCode == System.Windows.Forms.Keys.A)		//	Switch to the object at the given pixel location.
            {
                //  Get the currently active thing.
                TreeNode tn = Owner.Tv.SelectedNode;
                object switchFrom = null;
                if(tn!=null)
                    switchFrom = tn.Tag;
                //  If the polygon tool is operating, make sure the active thing is not a contour.
                //if( Owner.CurrentTool==ToolType.Polygon && switchFrom.GetType()==typeof(ContourF) )
                //    switchFrom = ((ContourF)switchFrom).PolyOwner;

                Point p = Owner.Pb.PointToClient(Cursor.Position);
                float x = Owner.PbToImgX((float)p.X);
                float y = Owner.PbToImgY((float)p.Y);

                CategoryNode cn = Owner.Opd.ActiveCategory;
                if(cn!=null)
                    cn = cn.PixExcludeNode;
                if(cn != null)
                {
                    PolygonFlist pList = new PolygonFlist();
                    cn.PolygonsContainingPoint(x,y,pList);
                    if(pList.Count>0)
                    {
                        if(pList.Count > 1)
                        {
                            PickObjectDialog pod = new PickObjectDialog(pList);
                            if(pod.ShowDialog() == DialogResult.OK)
                            {
                                //  The polygon to switch to
                                PolygonF switchTo = pod.SelectedPoly;
                                if( Owner.CurrentTool==ToolType.Contour && switchTo.Contours.Count > 0 )
                                {
                                    PointF ptf = new PointF(x,y);
                                    //  Pick the contour to switch to.
                                    float dMin, d;
                                    int iMin=0, i;
                                    dMin = switchTo.Contours[0].DistanceToLeg(ptf);
                                    for( i=1; i<switchTo.Contours.Count; i++ )
                                    {
                                        d = switchTo.Contours[i].DistanceToLeg(ptf);
                                        if( d<dMin )
                                        {
                                            iMin = i;
                                            dMin = d;
                                        }
                                    }
                                    if(switchTo.Contours[iMin] != switchFrom)
                                        Owner.ActivateSelection(switchTo.Contours[iMin],true);
                                }
                                else if(switchTo != switchFrom)
                                    Owner.ActivateSelection(switchTo,true);
                            }
                        }
                        else if(pList.Count == 1)
                        {
                            //  The polygon to switch to
                            PolygonF switchTo = pList[0];
                            if(Owner.CurrentTool==ToolType.Contour && switchTo.Contours.Count > 0)
                            {
                                PointF ptf = new PointF(x,y);
                                //  Pick the contour to switch to
                                float dMin,d;
                                int iMin=0,i;
                                dMin = switchTo.Contours[0].DistanceToLeg(ptf);
                                for(i=1;i<switchTo.Contours.Count;i++)
                                {
                                    d = switchTo.Contours[i].DistanceToLeg(ptf);
                                    if(d<dMin)
                                    {
                                        iMin = i;
                                        dMin = d;
                                    }
                                }
                                if(switchTo.Contours[iMin] != switchFrom)
                                    Owner.ActivateSelection(switchTo.Contours[iMin],true);
                            }
                            else if(switchTo != switchFrom)
                                Owner.ActivateSelection(switchTo,true);
                        }
                    }
                }
            }
            //  Insert a new parsed object, polygon, or contour.
            else if(e.KeyCode==Keys.Insert)
            {
                //  Get the currently active thing.
                TreeNode tnSel = Owner.Tv.SelectedNode;

                //  Make a new tree node and a new object
                if(tnSel.Tag.GetType()==typeof(CategoryNode))
                {
                    //  Add a new parsed object
                    CategoryNode super = (CategoryNode)tnSel.Tag;

                    int i;

                    //  See if there is an empty object in there.
                    ParsedObject po = null;
                    for(i=0;po==null && i<super.Objects.Count;i++)
                        if(super.Objects[i].Empty)
                            po = super.Objects[i];

                    //  No empty, make a new object
                    if(po==null)
                    {
                        po = new ParsedObject(Owner.Opd.ObjectCt++,super);
                        super.Objects.Add(po);
                    }

                    TreeNode node = new TreeNode(po.Name);
                    node.Tag = po;
                    node.ImageIndex = FormParse.ImageListIndex(po,false);
                    node.SelectedImageIndex = FormParse.ImageListIndex(po,true);

                    Cmd_AddNode cmd = new Cmd_AddNode(Owner,node,tnSel);

                    //  If the command is valid
                    if(cmd.Node!=null)
                    {
                        cmd.Redo();

                        Owner.UndoStack.Add(cmd);
                        Owner.RedoStack.Clear();
                    }
                }
                else if(tnSel.Tag.GetType()==typeof(ParsedObject))
                {
                    //  Add a new polygon
                    ParsedObject super = (ParsedObject)tnSel.Tag;
                    PolygonF poly = new PolygonF(super);
                    poly.Name = "polygon";
                    TreeNode node = new TreeNode(poly.Name);
                    node.ImageIndex = FormParse.ImageListIndex(poly,false);
                    node.SelectedImageIndex = FormParse.ImageListIndex(poly,true);
                    node.Tag = poly;

                    Cmd_AddNode cmd = new Cmd_AddNode(Owner,node,tnSel);

                    //  If the command is valid
                    if(cmd.Node!=null)
                    {
                        cmd.Redo();

                        Owner.UndoStack.Add(cmd);
                        Owner.RedoStack.Clear();
                    }
                }
                else if( tnSel.Tag.GetType().IsSubclassOf(typeof(PathF) ))
                {
                    //  Add a new contour
                    if(tnSel.Tag.GetType()==typeof(ContourF))
                        tnSel = tnSel.Parent;
                    PolygonF super = (PolygonF)tnSel.Tag;
                    ContourF con = new ContourF(super);
                    con.Name = "contour";
                    TreeNode node = new TreeNode(con.Name);
                    node.ImageIndex = FormParse.ImageListIndex(con,false);
                    node.SelectedImageIndex = FormParse.ImageListIndex(con,true);
                    node.Tag = con;

                    Cmd_AddNode cmd = new Cmd_AddNode(Owner,node,tnSel);

                    //  If the command is valid
                    if(cmd.Node!=null)
                    {
                        cmd.Redo();

                        Owner.UndoStack.Add(cmd);
                        Owner.RedoStack.Clear();
                    }
                }
                else if(tnSel.Tag.GetType()==typeof(Circle[]))
                {
                    //  Add a new circle
                    Circle cir = new Circle(new PointF(Owner.Opd.ImageWidth/2,Owner.Opd.ImageHeight/2),Math.Min(Owner.Opd.ImageWidth,Owner.Opd.ImageHeight)/4,true);
                    cir.Name = "ROI";
                    TreeNode node = new TreeNode(cir.Name);
                    node.ImageIndex = FormParse.ImageListIndex(cir,false);
                    node.SelectedImageIndex = FormParse.ImageListIndex(cir,true);
                    node.Tag = cir;

                    Cmd_AddNode cmd = new Cmd_AddNode(Owner,node,tnSel);

                    //  If the command is valid
                    if(cmd.Node!=null)
                    {
                        cmd.Redo();

                        Owner.UndoStack.Add(cmd);
                        Owner.RedoStack.Clear();
                    }
                }
            }
            //  Delete a category, parsed object, polygon, or contour.
            else if(e.KeyCode==Keys.Delete)
            {
                TreeNode node = Owner.Tv.SelectedNode;
                TreeNode tn = node.Parent;

                if(tn!=null)    //cannot delete a top level node
                {
                    Cmd_DeleteNode cmd = new Cmd_DeleteNode(Owner,node,tn);

                    //  If the command is valid
                    if(cmd.Node!=null)
                    {
                        cmd.Redo();

                        Owner.UndoStack.Add(cmd);
                        Owner.RedoStack.Clear();
                    }
                }
            }
            else if((e.KeyCode==Keys.L) || (e.KeyCode==Keys.Escape && LinkMode))
            {
                ToggleLinkMode();
            }
            //	Cancel bridge making
            else if(e.KeyCode==Keys.Escape && NewBridge!=null)
            {
                NewBridge = null;
                Owner.Pb.Invalidate();
            }
            #region S -- Swallow a polygon
            //	Swalow
            else if(e.KeyCode == System.Windows.Forms.Keys.S)		//	Swallow the object at the given pixel location.
            {
                PolygonF activePoly = Owner.Opd.ActivePoly;
                if(activePoly != null)
                {
                    Point p = Owner.Pb.PointToClient(Cursor.Position);
                    float x = Owner.PbToImgX((float)p.X);
                    float y = Owner.PbToImgY((float)p.Y);

                    PolygonFlist pArray = Owner.Opd.PolysContainingPoint(x,y,false);
                    PolygonFlist toSwallow = new PolygonFlist();
                    if(pArray.Count > 1)
                    {
                        PickObjectDialog pod = new PickObjectDialog(pArray);
                        if(pod.ShowDialog() == DialogResult.OK)
                            toSwallow.Add(pod.SelectedPoly);
                    }
                    else if(pArray.Count == 1)
                        toSwallow.Add(pArray[0]);

                    if(toSwallow.Count > 0)
                    {
                        if(toSwallow[0].Swallowed.Contains(activePoly))		//	And if the active polygon has not already swallowed the toSwallow polygon
                        {	//	Swallowing operation cannot continue.  The polygon in question is not swallowable.
                            MessageBox.Show(this.Owner,"Swallowing operation cannot continue.  The polygon "+ toSwallow[0].ToString() +" cannot be swallowed" + 
								    "because it has already swallowed the active polygon.","Requested action could not be executed.");
                            toSwallow.Clear();
                        }
                    }
                    if(toSwallow.Count>0 && (activePoly.Swallowed.Contains(toSwallow[0]) || toSwallow[0].SwallowedBy!=null))
                        toSwallow.Clear();
                    if(toSwallow.Count>0)
                    {
                        //	Swallowing requires doubly linking two lists.
                        activePoly.Swallowed.Add(toSwallow[0]);
                        toSwallow[0].SwallowedBy = activePoly;
                        //	Swallowing means invalidating the toSwallow[i] polygon.
                        Owner.Pb.Invalidate(Owner.InvPbRect(Owner.ImgToPbRect(toSwallow[0].GetBoundingRect(1))));
                        //	Swallow a polygon, Undo encoding:
                        //  ( PolygonFlist toSwallow )
                        ArrayList macro = new ArrayList();
                        macro.Add(110);
                        macro.Add(toSwallow);	//	list of polygons to swallow.
                        Owner.UndoStack.Add(macro);
                        Owner.RedoStack.Clear();
                    }
                }
            }
            #endregion
            #region U -- Unswallow a polygon
            //	Unswallow a polygon
            else if(e.KeyCode == System.Windows.Forms.Keys.U)
            {
                PolygonF activePoly = Owner.Opd.ActivePoly;
                if(activePoly != null)
                {
                    Point p = Owner.Pb.PointToClient(Cursor.Position);
                    float x = Owner.PbToImgX((float)p.X);
                    float y = Owner.PbToImgY((float)p.Y);

                    PolygonFlist pArray = Owner.Opd.PolysContainingPoint(x,y,false);
                    PolygonFlist toUnswallow = new PolygonFlist();
                    if(pArray.Count > 1)
                    {
                        PickObjectDialog pod = new PickObjectDialog(pArray);
                        if(pod.ShowDialog() == DialogResult.OK)
                            toUnswallow.Add(pod.SelectedPoly);
                    }
                    else if(pArray.Count == 1)
                        toUnswallow.Add(pArray[0]);

                    if(toUnswallow.Count > 0)
                    {
                        //	Swallowing requires doubly linking two lists.
                        int ind = activePoly.Swallowed.IndexOf(toUnswallow[0]);
                        if(ind > -1)
                        {
                            activePoly.Swallowed.RemoveAt(ind);
                            toUnswallow[0].SwallowedBy = null;
                            //	Swallowing means invalidating the toSwallow[i] polygon.
                            Owner.Pb.Invalidate(Owner.InvPbRect(Owner.ImgToPbRect(toUnswallow[0].GetBoundingRect(1))));
                            //	Swallow a polygon, Undo encoding:
                            //  ( PolygonFlist toSwallow )
                            ArrayList macro = new ArrayList();
                            macro.Add(111);
                            macro.Add(toUnswallow);	//	list of polygons to swallow.
                            Owner.UndoStack.Add(macro);
                            Owner.RedoStack.Clear();
                        }
                    }
                }
            }
            #endregion
            #region P -- Pull out of a link
            else if(e.KeyCode == System.Windows.Forms.Keys.P)	//	Pull a point out of a link
            {
                PolygonF activePoly = Owner.Opd.ActivePoly;
                ContourF activeCon = null;
                if(Owner.CurrentTool==ToolType.Contour)
                    activeCon = Owner.Opd.ActiveContour;
                PathF activePath = activePoly;
                if(activeCon != null)
                    activePath = activeCon;
                if(activePath != null && DrawPts[0] && ImgLeg[0].Polygons.Count+ImgLeg[0].Contours.Count > 1)
                {
                    if(activePath.Count<=1)	//	Delete the current path.
                    {
                        TreeNode node=this.Owner.NodeAttachedTo(activePath);
                        if(activeCon == null && activePoly.Owner.Polygons.Count > 1)
                            node=this.Owner.NodeAttachedTo(activePoly);
                        else if(activeCon != null && activeCon.PolyOwner.Contours.Count > 1)
                            node=this.Owner.NodeAttachedTo(activeCon);
                        Cmd_DeleteNode cmd = new Cmd_DeleteNode(this.Owner,node,node.Parent);
                        cmd.Redo();
                        Owner.UndoStack.Add(cmd);
                        Owner.RedoStack.Clear();

                        /*
                        //	(107)	Delete a thing and switch to the last active thing.
                        //	( CategoryNode or ParsedObject or PolygonF delThing,
                        //		CategoryNode or ParsedObject or PolygonF nextActiveThing
                        //		EdgePairArray bustedEdges)
                        ArrayList macro = new ArrayList();
                        macro.Add(107);
                        if(activeCon == null && activePoly.Owner.Polygons.Count > 1)
                        {
                            macro.Add(activePoly);
                            macro.Add(activePoly.Owner.PreviousPoly);
                        }
                        else if(activeCon != null && activeCon.PolyOwner.Contours.Count > 1)
                        {
                            macro.Add(activeCon);
                            macro.Add(activeCon.PolyOwner.PreviousContour);
                        }
                        else
                        {
                            macro.Add(activePath);
                            macro.Add(activePoly.Owner.Category);
                        }
                        macro.Add(null);	//	for storing edge validation.

                        //	execute the deletion.
                        Owner.ExecuteAction(true,macro,true);

                        Owner.UndoStack.Add(macro);
                        Owner.RedoStack.Clear();
                        */
                    }
                    else if(activePoly.Count==2)
                    {
                        //	(109)	Unlink a VertexF vf from the PolygonF pf
                        //  (VertexF vf, PolygonF pf, int ind, PolygonFlist toSwallow, EdgePairArray bustedEdges)
                        ArrayList macro = new ArrayList();
                        macro.Add(109);
                        macro.Add(ImgLeg[0]);
                        macro.Add(activePath);
                        macro.Add(activePath.IndexOf(ImgLeg[0]));
                        macro.Add(null);	//	For storing the list of polygons to swallow (for Undo).
                        macro.Add(null);	//	For storing the edge validation (for Undo).

                        //	execute the unlink.
                        Owner.ExecuteAction(true,macro,true);

                        Owner.UndoStack.Add(macro);
                        Owner.RedoStack.Clear();
                    }
                    else //activePoly.Count > 2
                    {
                        int ind = activePath.IndexOf(ImgLeg[0]);
                        PolygonF changedRegion = new PolygonF(null);
                        if(activePath.GetType()==typeof(PolygonF))
                        {
                            int last = VertexF.LastInd(activePath.Count,ind);
                            int next = VertexF.NextInd(activePath.Count,ind);
                            changedRegion.Add(activePath[last]);
                            changedRegion.Add(activePath[ind]);
                            changedRegion.Add(activePath[next]);
                            ImgLeg[0].Polygons.Remove(activePath);
                        }
                        else if(activePath.GetType()==typeof(ContourF))
                        {
                            int last = ind-1;
                            int next = ind+1;
                            if(last>=0)
                                changedRegion.Add(activePath[last]);
                            changedRegion.Add(activePath[ind]);
                            if(next < activePath.Count)
                                changedRegion.Add(activePath[next]);
                            ImgLeg[0].Contours.Remove(activePath);
                        }
                        activePath.RemoveAt(ind);

                        bool stable = true;

                        if(activePath.IntersectsSelf())
                            stable = false;

                        //	Check for a leg-crossing violation
                        for(int i=0;i<ImgLeg[0].Polygons.Count;i++)
                            if(ImgLeg[0].Polygons[i].IntersectsSelf())
                                stable = false;
                        for(int i=0;i<ImgLeg[0].Contours.Count;i++)
                            if(ImgLeg[0].Contours[i].IntersectsSelf())
                                stable = false;

                        PolygonFlist toSwallow = new PolygonFlist();

                        //	Check for a swallowing violation
                        if(stable && activePath.GetType()==typeof(PolygonF))
                        {
                            PolygonFlist unstable = Owner.Opd.RegionIsStable(changedRegion);

                            if(unstable.Count > 1)	//	Swallowing violation detected
                            {
                                if(DialogResult.OK==MessageBox.Show(this.Owner,"Swallow unstable polygons with the active polygon?",
                                    "Pixel exclusivity violation detected.",MessageBoxButtons.OKCancel))
                                {	//	Check to make sure that all polygons can be swallowed.
                                    for(int i=0;i<unstable.Count;i++)
                                    {
                                        if(unstable[i] != activePoly)		//	If the unstable polygon is not the active polygon
                                        {
                                            if(unstable[i].Owner == activePoly.Owner)	//	If the unstable and active polygons do not have the same owner.
                                            {
                                                stable = false;
                                                toSwallow.Clear();
                                                MessageBox.Show(this.Owner,"Swallowing operation cannot continue.  The polygon "+ unstable[i].ToString() +" cannot be swallowed" + 
													    " by the active polygon because both polygons are part of the same object.","Requested action was not executed.");
                                            }

                                            if(stable && unstable[i].SharesVertexWith(activePoly))
                                            {
                                                stable = false;
                                                toSwallow.Clear();
                                                MessageBox.Show(this.Owner,"Swallowing operation cannot continue.  The polygon "+ unstable[i].ToString() +" cannot be swallowed" + 
													    " by the active polygon because the polygons share at least one common vertex.","Requested action was not executed.");
                                            }
                                            if(stable && unstable[i].Swallowed.Contains(activePoly))
                                            {
                                                stable = false;
                                                toSwallow.Clear();
                                                MessageBox.Show(this.Owner,"Swallowing operation cannot continue.  The polygon "+ unstable[i].ToString() +" cannot be swallowed" + 
													    " by the active polygon it has already swallowed the active polygon.","Requested action was not executed.");
                                            }
                                            if(stable && unstable[i].SwallowedBy!=null)
                                            {
                                                stable = false;
                                                toSwallow.Clear();
                                                MessageBox.Show(this.Owner,"Swallowing operation cannot continue.  The polygon "+ unstable[i].ToString() +" cannot be swallowed" + 
													    " because it is already swallowed by " +unstable[i].SwallowedBy.ToString(),"Requested action was not executed.");
                                            }
                                            if(stable && unstable[i].Swallowed.Contains(activePoly))		//	And if the active polygon has not already swallowed the unstable polygon
                                            {
                                                //	Swallowing operation cannot continue.  The polygon in question is not swallowable.
                                                stable = false;
                                                toSwallow.Clear();
                                                MessageBox.Show(this.Owner,"Swallowing operation cannot continue.  The polygon "+ unstable[i].ToString() +" cannot be swallowed." + 
													    "It is already swallowing the active polygon.","Requested action could not be executed.");
                                            }
                                            if(stable)
                                            {
                                                toSwallow.Add(unstable[i]);
                                            }
                                        }
                                    }

                                    //	Swallow.
                                    for(int i=0;i<toSwallow.Count;i++)
                                    {
                                        //	Swallowing requires doubly linking two lists.
                                        activePoly.Swallowed.Add(toSwallow[i]);
                                        toSwallow[i].SwallowedBy = activePoly;
                                        //	Swallowing means invalidating the toSwallow[i] polygon.
                                        Owner.Pb.Invalidate(Owner.InvPbRect(Owner.ImgToPbRect(toSwallow[i].GetBoundingRect(1))));
                                    }
                                }
                                else
                                {	//	Don't swallow, Undo().
                                    stable = false;
                                }
                            }
                        }
                        if(stable)
                        {
                            //	(109)	Unlink a VertexF vf from the PolygonF pf
                            //  (VertexF vf, PolygonF pf, int ind, PolygonFlist toSwallow, EdgePairArray bustedEdges)
                            ArrayList macro = new ArrayList();
                            macro.Add(109);
                            macro.Add(ImgLeg[0]);
                            macro.Add(activePath);
                            macro.Add(ind);
                            macro.Add(toSwallow);
                            macro.Add(activePoly.ValidateEdges());

                            Owner.UndoStack.Add(macro);
                            Owner.RedoStack.Clear();

                            if(activePath.GetType()==typeof(PolygonF))
                                ((PolygonF)activePath).AfterRemoveVertexF(ind,ImgLeg[0],Owner.BmpCurrentObj,Owner.Opd.ObjCurrColor);

                            UpdateVertexDraw();
                            UpdateInactivePaths();
                        }
                        else
                        {
                            activePath.Insert(ind,ImgLeg[0]);
                            if(activePath.GetType()==typeof(PolygonF))
                                ImgLeg[0].Polygons.Add(activePath);
                            else
                                ImgLeg[0].Contours.Add(activePath);
                        }
                    }
                }
            }
            #endregion
            #region F -- Full claim of Edges for the active poly
            //	Claim all edges (Full enclosure)
            else if(e.KeyCode == Keys.F)
            {
                PolygonF activePoly = Owner.Opd.ActivePoly;
                if(activePoly!=null)
                {
                    //	Claim all the edges for a new owner (i.e. the active polygon)
                    //	(122, PolygonF newOwner, EdgePairArray disownedEdges, ArrayList(int) lastOwnerInd)
                    Cmd_ClaimAllEdges cmd = new Cmd_ClaimAllEdges(activePoly);

                    Owner.UndoStack.Add(cmd);
                    Owner.RedoStack.Clear();

                    cmd.Redo();
                    Owner.Pb.Invalidate();
                }
            }
            #endregion
            #region E -- Eat unclaimed edges
            //	Claim all edges (Full enclosure)
            else if(e.KeyCode == Keys.E)
            {
                PolygonF activePoly = Owner.Opd.ActivePoly;
                if(activePoly!=null)
                {

                    //	Eat the unclaimed edges for a new owner (i.e. the active polygon)
                    //	(123, PolygonF newOwner, EdgePairArray disownedEdges)
                    Cmd_ClaimUnclaimedEdges cmd = new Cmd_ClaimUnclaimedEdges(activePoly);

                    Owner.UndoStack.Add(cmd);
                    Owner.RedoStack.Clear();

                    cmd.Redo();
                    Owner.Pb.Invalidate();
                }
            }
            #endregion
            #region R -- Release the active Edge
            //	Release the active Edge.
            else if(e.KeyCode == Keys.R)
            {
                PolygonF activePoly = Owner.Opd.ActivePoly;
                if(activePoly!=null && activePoly.Count>2 && ImgLeg[0].Polygons.Contains(activePoly))
                {
                    int ind = activePoly.EdgeGroups.UniqueVertexOwner(ImgLeg[0],ImgLeg[1]);
                    EdgeGroup eg=null;
                    Edge fe = null;
                    if(ind>=0)
                        eg = activePoly.EdgeGroups[ind];
                    if(eg!=null)
                        fe = eg.DominantEdge;
                    if(eg!=null && fe!=null && fe.Owner==activePoly)
                    {
                        //	Release a full edge.
                        //	(121, EdgePair fep, PolygonF oldOwner)
                        Cmd_ReleaseEdge cmd = new Cmd_ReleaseEdge(eg,activePoly);

                        Owner.UndoStack.Add(cmd);
                        Owner.RedoStack.Clear();

                        cmd.Redo();
                        Owner.Pb.Invalidate();
                    }
                }
            }
            #endregion
            #region T -- Take (claim) the active Edge into the active polygon.
            //	Take (Claim) the active Edge.
            else if(e.KeyCode == Keys.T)
            {
                PolygonF activePoly = Owner.Opd.ActivePoly;
                if(activePoly!=null && activePoly.Count>2 && ImgLeg[0].Polygons.Contains(activePoly))
                {
                    int ind = activePoly.EdgeGroups.UniqueVertexOwner(ImgLeg[0],ImgLeg[1]);
                    EdgeGroup eg=null;
                    if(ind>=0)
                        eg = activePoly.EdgeGroups[ind];
                    if(eg!=null)
                    {
                        Edge fe = eg.DominantEdge;
                        //	Take (Claim) a full edge.
                        Cmd_ClaimEdge cmd = null;
                        if(fe==null)
                            cmd = new Cmd_ClaimEdge(eg,null,activePoly);
                        else
                            cmd = new Cmd_ClaimEdge(eg,fe.Owner,activePoly);

                        //  Store command
                        Owner.UndoStack.Add(cmd);
                        Owner.RedoStack.Clear();

                        //  Execute command
                        cmd.Redo();
                        Owner.Pb.Invalidate();
                    }
                }
            }
            #endregion
            #region G -- Give the active Edge to the owner of the Twin Edge
            //	Give the active Edge to the Twin.
            else if(e.KeyCode == Keys.G)
            {
                PolygonF activePoly = Owner.Opd.ActivePoly;
                if(activePoly!=null && activePoly.Count>2 && ImgLeg[0].Polygons.Contains(activePoly))
                {
                    int ind = activePoly.EdgeGroups.UniqueVertexOwner(ImgLeg[0],ImgLeg[1]);
                    EdgeGroup eg=null;
                    if(ind>=0)
                        eg = activePoly.EdgeGroups[ind];
                    if(eg!=null && !eg.IsSingular)
                    {
                        Edge feDom = eg.DominantEdge;

                        //	Only go ahead if the dominant edge is not already given away.
                        if(feDom==null || feDom.Owner==activePoly)
                        {
                            Edge feSub = eg.EdgeOfAnotherPoly(activePoly);
                            if(feSub!=null)
                            {
                                //	Take (Claim) a full edge.
                                //	(120, EdgeGroup eg, PolygonF oldOwner, PolygonF newOwner)
                                Cmd_ClaimEdge cmd = null;
                                if(feDom==null)
                                    cmd = new Cmd_ClaimEdge(eg,null,feSub.Owner);
                                else
                                    cmd = new Cmd_ClaimEdge(eg,feDom.Owner,feSub.Owner);

                                //  Store command
                                Owner.UndoStack.Add(cmd);
                                Owner.RedoStack.Clear();

                                //  Execute command
                                cmd.Redo();
                                Owner.Pb.Invalidate();
                            }
                        }
                    }
                }
            }
            #endregion
            #region B -- Bridge
            //	Bridge
            else if(e.KeyCode == Keys.B)
            {
                //	Cancel bridge making
                if(NewBridge!=null)
                {
                    NewBridge = null;
                    Owner.Pb.Invalidate();
                }
                else
                {
                    PolygonF activePoly = Owner.Opd.ActivePoly;
                    if(activePoly!=null && activePoly.Count>2 && !LinkMode)
                    {
                        ParsedObject po = activePoly.Owner;

                        //	Check to see if a bridge should be destroyed
                        OcclusionBridge destroyed = null;
                        for(int i=0;i<po.Bridges.Count;i++)
                        {
                            destroyed = po.Bridges[i];
                            if(destroyed.Vf1==ImgLeg[0] || destroyed.Vf2==ImgLeg[0])
                            {
                                po.Bridges.RemoveAt(i);
                                break;
                            }
                            destroyed = null;
                        }
                        if(destroyed!=null)
                        {
                            ArrayList macro = new ArrayList();
                            macro.Add(131);
                            macro.Add(destroyed);
                            macro.Add(activePoly.ValidateEdges());
                            Owner.UndoStack.Add(macro);
                            Owner.RedoStack.Clear();

                            Owner.Pb.Invalidate();
                        }
                        else	//	If no destoying, then start a new bridge.
                        {
                            //	There is an active polygon belonging to an object with at least
                            //	2 total polygons.
                            //	Find the VertexF on a neighboring polygon (of the same ParsedObject)
                            //	that is closest to the mouse pointer.
                            PolygonF pf;
                            VertexF vf;
                            po.ClosestVertexF(Owner.PbToImg(Owner.Pb.PointToClient(Cursor.Position)),
                                null,out pf,out vf);
                            if(vf!=null)
                            {
                                if(vf.Polygons.Contains(activePoly))
                                    pf = activePoly;
                                NewBridge = new OcclusionBridge(activePoly,ImgLeg[0],pf,vf);
                                Owner.Pb.Invalidate(VertexF.GetBoundingRect(
                                    Owner.ImgToPb(ImgLeg[0]),Owner.ImgToPb(vf),2.0f));
                            }
                        }
                    }
                }
            }
            #endregion
        }
        public void OnPb_SizeChanged(object sender,System.EventArgs e)
        {
            //	Update the polygon points.
            UpdateInactivePaths();
            for(int i=0;i<2;i++)
                if(DrawPts[i])
                {
                    PbLeg[i].X = Owner.ImgToPbX(ImgLeg[i].X);
                    PbLeg[i].Y = Owner.ImgToPbY(ImgLeg[i].Y);
                    _PbLeg[i].X = Owner.ImgToPbX(_ImgLeg[i].X);
                    _PbLeg[i].Y = Owner.ImgToPbY(_ImgLeg[i].Y);
                }
        }
        public void OnPb_MouseEnter(object sender,System.EventArgs e)
        {
            Cursor.Current = Cursors.Cross;
        }
        public void OnMouseWheel(object sender,MouseEventArgs e)
        {
            if(LinkMode)
            {
                UpdateLinkDraw();
                if(LinkStage > 2)
                    Glider.UpdateDrawCache();
            }
            else
            {
                //	Update the polygon points.
                UpdateInactivePaths();
                for(int i=0;i<2;i++)
                    if(DrawPts[i])
                    {
                        PbLeg[i].X = Owner.ImgToPbX(ImgLeg[i].X);
                        PbLeg[i].Y = Owner.ImgToPbY(ImgLeg[i].Y);
                        _PbLeg[i].X = Owner.ImgToPbX(_ImgLeg[i].X);
                        _PbLeg[i].Y = Owner.ImgToPbY(_ImgLeg[i].Y);
                    }
            }
        }
        public void OnPaint(object sender,System.Windows.Forms.PaintEventArgs e)
        {
            PolygonF activePoly = this.Owner.Opd.ActivePoly;
            ContourF activeContour = null;
            if(Owner.CurrentTool==ToolType.Contour)
                activeContour = Owner.Opd.ActiveContour;
            PathF path;
            PointF[] points;
            int i;

            //	Toggles the option to display nothing besides the image.
            if(Owner.bViewAll.ImageIndex==1)
            {
                //	Draw the active polygon if its the only one to be drawn.
                if(activePoly != null && Owner.bViewPoly.ImageIndex==1)
                {
                    DrawPoly(sender,e,activePoly,false,true);
                }
                //	Draw the active contour if its the only one to be drawn.
                if(activeContour!=null && Owner.bViewContours.ImageIndex==1)
                {
                    DrawContour(sender,e,activeContour,false,true);
                }

                //	A bridge is being created, so draw it.
                if(NewBridge != null)
                {
                    e.Graphics.DrawLine(this.PenLineDash,
                        Owner.ImgToPb(NewBridge.Vf1),Owner.ImgToPb(NewBridge.Vf2));
                    e.Graphics.DrawEllipse(this.PenPtThick,VertexF.GetPtDrawRect(NewBridge.Vf2,RADIUS));
                }
                else if(LinkMode)
                {
                    //	Stage 1:  The "L" button was just selected and we enter LinkMode.  User must select Base 1.
                    //	Stage 2:  User must select Target 1.
                    //	Stage 3:  GlidePath to select Target 2.
                    //	Stage 4:  User must select Base 2 (there will only be two possibilities)
                    if(LinkStage==1)
                    {
                        //	Highlight the potential Base 1 by drawing a circle around the point LmPbBase with the PenLine
                        e.Graphics.DrawEllipse(this.PenPtThick,VertexF.GetPtDrawRect(LmPbBase1,RADIUS));
                        //	Draw all inactive paths
                        for(i=0;i<InactivePaths.Count;i++)
                        {
                            path = (PathF)InactivePaths[i];
                            points = path.PbPath;
                            if(points.Length > 2)
                            {
                                if(path.GetType()==typeof(PolygonF))
                                    e.Graphics.DrawPolygon(this.PenPtDot,points);
                                else
                                    e.Graphics.DrawLines(this.PenPtDot,points);
                            }
                            else
                                e.Graphics.DrawLine(this.PenLine,points[0],points[1]);
                        }
                    }
                    else if(LinkStage==2)
                    {
                        //	Highlight the potential Target 1.  Draw a line from Base1 to Target 1.
                        e.Graphics.DrawEllipse(PenPtThick,VertexF.GetPtDrawRect(LmPbTar1,RADIUS));
                        e.Graphics.DrawLine(PenLine,LmPbBase1,LmPbTar1);
                        //	Draw all inactive paths
                        for(i=0;i<InactivePaths.Count;i++)
                        {
                            path = (PathF)InactivePaths[i];
                            points = path.PbPath;
                            if(points.Length > 2)
                            {
                                if(path.GetType()==typeof(PolygonF))
                                    e.Graphics.DrawPolygon(this.PenPtDot,points);
                                else
                                    e.Graphics.DrawLines(this.PenPtDot,points);
                            }
                            else
                                e.Graphics.DrawLine(this.PenLine,points[0],points[1]);
                        }
                    }
                    else if(LinkStage==3)
                    {
                        //	Glide path to Target 2 until OnMouseDown, auto-select base 2.
                        Glider.Draw(e.Graphics,this.PenPtThick);
                        e.Graphics.DrawLine(PenLine,LmPbBase1,LmPbTar1);
                        //	Draw all inactive paths
                        for(i=0;i<InactivePaths.Count;i++)
                        {
                            path = (PathF)InactivePaths[i];
                            points = path.PbPath;
                            if(points.Length > 2)
                            {
                                if(path.GetType()==typeof(PolygonF))
                                    e.Graphics.DrawPolygon(this.PenPtDot,points);
                                else
                                    e.Graphics.DrawLines(this.PenPtDot,points);
                            }
                            else
                                e.Graphics.DrawLine(this.PenLine,points[0],points[1]);
                        }
                    }
                    if(LinkStage==4)
                    {
                        //	Glide path to Target 2 until OnMouseDown, auto-select base 2.
                        Glider.Draw(e.Graphics,this.PenPtThick);
                        //	Highlight the potential Base 2 by drawing a circle around the point LmPbBase
                        e.Graphics.DrawEllipse(PenPtThick,VertexF.GetPtDrawRect(LmPbBase2,RADIUS));
                        //	Draw all inactive paths
                        for(i=0;i<InactivePaths.Count;i++)
                        {
                            path = (PathF)InactivePaths[i];
                            points = path.PbPath;
                            if(points.Length > 2)
                            {
                                if(path.GetType()==typeof(PolygonF))
                                    e.Graphics.DrawPolygon(this.PenPtDot,points);
                                else
                                    e.Graphics.DrawLines(this.PenPtDot,points);
                            }
                            else
                                e.Graphics.DrawLine(this.PenLine,points[0],points[1]);
                        }
                        e.Graphics.DrawLine(PenLine,LmPbBase1,LmPbTar1);
                        if(Glider.DrawCache!=null && Glider.DrawCache.Length>0)
                            e.Graphics.DrawLine(PenLine,LmPbBase2,Glider.DrawCache[Glider.Count-1]);
                    }
                }
                if(Owner.bViewPoly.ImageIndex>=1 || Owner.bViewContours.ImageIndex>=1)
                {
                    //	Draw active vertices
                    if(Owner.bViewVertices.ImageIndex>0 && !LinkMode)
                    {
                        if(MovingPathPt)
                            e.Graphics.DrawEllipse(PenPt,VertexF.GetPtDrawRect(PbStylus,RADIUS));
                        else
                        {
                            if(DrawPts[0])
                                e.Graphics.DrawEllipse(this.PenPt,VertexF.GetPtDrawRect(PbLeg[0],RADIUS));
                            if((!CtrlKeyIsDown) && DrawPts[1])
                                e.Graphics.DrawEllipse(this.PenPtDot,VertexF.GetPtDrawRect(PbLeg[1],RADIUS));
                        }
                    }
                    //	Draw inactive paths
                    for(i=0;i<InactivePaths.Count;i++)
                    {
                        path = (PathF)InactivePaths[i];
                        if(path.GetType()==typeof(PolygonF) && Owner.bViewPoly.ImageIndex==1)	//	Polygon
                            this.DrawPoly(sender,e,path,false,false);
                    }
                    if(Owner.bViewPoly.ImageIndex>1)
                        DrawPoly(sender,e,Owner.Opd.ActiveCategory,true,true);
                }
                //	Draw inactive contours
                if(activePoly!=null && Owner.bViewContours.ImageIndex == 1)
                    for(i=0;i<activePoly.Contours.Count;i++)
                        DrawContour(sender,e,activePoly.Contours[i],false,false);
                if(Owner.bViewContours.ImageIndex>1)
                    DrawContour(sender,e,Owner.Opd.ActiveCategory,true,false);
            }
            //	Draw full edges only if the menu option to view the active edges is selected.
            if(Owner.bViewEdges.ImageIndex==1 && activePoly!=null)
            {
                //	Refresh edges for inactive polys if necessary
                if((activePoly.EdgeGroups==null || activePoly.EdgeGroups.Count==0))
                    activePoly.CalcEdges();
                DrawEdge(sender,e,activePoly.Owner,true,true);
            }
            else if(Owner.bViewEdges.ImageIndex >	1)
            {
                //	Refresh edges for inactive polys if necessary
                if((activePoly.EdgeGroups==null || activePoly.EdgeGroups.Count==0))
                    activePoly.CalcEdges();
                DrawEdge(sender,e,Owner.Opd.ActiveCategory,true,false);
            }
        }
        public void DrawPoly(object sender,System.Windows.Forms.PaintEventArgs e,object obj,bool doRecursion,bool drawAsActive)
        {
            if(obj!=null)
            {
                int i;
                if(obj.GetType()==typeof(CategoryNode))
                {
                    CategoryNode cn = (CategoryNode)obj;
                    bool da = drawAsActive && Owner.Opd.ActiveCategory==cn;
                    for(i=0;i<cn.Objects.Count;i++)
                        DrawPoly(sender,e,cn.Objects[i],doRecursion,da && cn.ActiveObjectInd==i);
                    if(doRecursion)
                        for(i=0;i<cn.Sub.Count;i++)
                            DrawPoly(sender,e,cn.Sub[i],true,drawAsActive);
                }
                else if(obj.GetType()==typeof(ParsedObject))
                {
                    ParsedObject po = (ParsedObject)obj;
                    for(i=0;i<po.Polygons.Count;i++)
                        DrawPoly(sender,e,po.Polygons[i],doRecursion,po.ActivePolyInd==i && drawAsActive);
                }
                else if(obj.GetType()==typeof(PolygonF))
                {
                    PolygonF pf = (PolygonF)obj;
                    Pen pen = (Pen)PenLine.Clone();
                    if(pf.Color!=Color.Transparent)
                        pen.Color = pf.Color;
                    //	Draw the polygon.
                    PointF[] points = pf.PbPath;
                    if(points.Length > 2)
                        e.Graphics.DrawPolygon(pen,points);
                    else if(points.Length > 1)
                        e.Graphics.DrawLine(pen,points[0],points[1]);
                    if(drawAsActive)
                    {
                        //	Draw the swallowing polygon
                        LastPaintedSwallowedBy = pf.SwallowedBy;
                        if(pf.SwallowedBy != null && pf.SwallowedBy.Count > 2)
                            e.Graphics.DrawPolygon(this.PenRedLine,pf.SwallowedBy.PbPath);
                        //	Draw swallowed polygon
                        LastPaintedSwallowed = pf.Swallowed;
                        for(i=0;i<pf.Swallowed.Count;i++)
                            if(pf.Swallowed[i].Count > 2)
                                e.Graphics.DrawPolygon(this.PenBlueLine,pf.Swallowed[i].PbPath);
                    }
                }
            }
        }
        public void DrawContour(object sender,System.Windows.Forms.PaintEventArgs e,object obj,bool doRecursion,bool drawAsActive)
        {
            if(obj!=null)
            {
                int i;
                if(obj.GetType()==typeof(CategoryNode))
                {
                    CategoryNode cn = (CategoryNode)obj;
                    bool da = drawAsActive && Owner.Opd.ActiveCategory==cn;
                    for(i=0;i<cn.Objects.Count;i++)
                        DrawContour(sender,e,cn.Objects[i],doRecursion,da && cn.ActiveObjectInd==i);
                    if(doRecursion)
                        for(i=0;i<cn.Sub.Count;i++)
                            DrawContour(sender,e,cn.Sub[i],true,drawAsActive);
                }
                else if(obj.GetType()==typeof(ParsedObject))
                {
                    ParsedObject po = (ParsedObject)obj;
                    for(i=0;i<po.Polygons.Count;i++)
                        DrawContour(sender,e,po.Polygons[i],doRecursion,po.ActivePolyInd==i && drawAsActive);
                }
                else if(obj.GetType()==typeof(PolygonF))
                {
                    PolygonF pf = (PolygonF)obj;
                    for(i=0;i<pf.Contours.Count;i++)
                        DrawContour(sender,e,pf.Contours[i],doRecursion,pf.ActiveContourInd==i && drawAsActive);
                }
                else if(obj.GetType()==typeof(ContourF))
                {
                    ContourF cf = (ContourF)obj;
                    PointF[] points = cf.PbPath;
                    if(points!=null)
                    {
                        Pen pen = (Pen)PenLine.Clone();
                        if(!drawAsActive)
                            pen = (Pen)PenPtDot.Clone();
                        if(cf.Color!=Color.Transparent)
                            pen.Color = cf.Color;
                        if(points.Length > 2)
                            e.Graphics.DrawLines(pen,points);
                        else if(points.Length > 1)
                            e.Graphics.DrawLine(pen,points[0],points[1]);
                    }
                }
            }
        }
        public void DrawEdge(object sender,System.Windows.Forms.PaintEventArgs e,object obj,bool doRecursion,bool drawAsActive)
        {
            if(obj!=null)
            {
                if(obj.GetType()==typeof(CategoryNode))
                {
                    CategoryNode cn = (CategoryNode)obj;
                    int i;
                    for(i=0;i<cn.Objects.Count;i++)
                        DrawEdge(sender,e,cn.Objects[i],doRecursion,drawAsActive && cn.ActiveObjectInd==i);
                    if(doRecursion)
                        for(i=0;i<cn.Sub.Count;i++)
                            DrawEdge(sender,e,cn.Sub[i],true,drawAsActive);
                }
                else if(obj.GetType()==typeof(ParsedObject))
                {
                    //	Draw full edges
                    PointF[] pbEdge;
                    Edge fe;
                    ParsedObject po = (ParsedObject)obj;
                    PolygonF pf;
                    drawAsActive = drawAsActive && po==po.Category.ActiveObject;
                    int i,j;
                    for(i=0;i<po.Polygons.Count;i++)
                    {
                        pf = po.Polygons[i];
                        if(pf!=null)
                        {
                            if(pf.EdgeGroups==null)
                                pf.CalcEdges();
                            for(j=0;j<pf.EdgeGroups.Count;j++)
                            {
                                //	Dominant edge
                                fe = pf.EdgeGroups[j].DominantEdge;
                                //	Draw
                                if(fe!=null)
                                {
                                    pbEdge = fe.PbEdgeIn(3.0f,true);
                                    if(pbEdge!=null && pbEdge.Length>=2)
                                    {
                                        if(fe.Owner==pf)
                                            e.Graphics.DrawLines(PenEdgeIn,pbEdge);
                                        else if(drawAsActive && fe.Owner.Owner!=po)
                                            e.Graphics.DrawLines(PenEdgeOut,pbEdge);
                                    }
                                }
                            }
                        }
                    }
                    //	Draw the bridges
                    OcclusionBridge bridge;
                    for(i=0;i<po.Bridges.Count;i++)
                    {
                        bridge = po.Bridges[i];
                        e.Graphics.DrawLine(this.PenLineDash,
                            Owner.ImgToPb(bridge.Vf1),Owner.ImgToPb(bridge.Vf2));
                    }
                }
                else if(obj.GetType()==typeof(PolygonF))
                {
                    DrawEdge(sender,e,((PolygonF)obj).Owner,doRecursion,drawAsActive);
                }
            }
        }
    }
}